-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
622 lines (582 loc) · 110 KB
/
Copy pathatom.xml
File metadata and controls
622 lines (582 loc) · 110 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<title>Lockbook</title>
<subtitle>An open-source, end-to-end encrypted notebook.</subtitle>
<link rel="self" type="application/atom+xml" href="https://lockbook.net/atom.xml"/>
<link rel="alternate" type="text/html" href="https://lockbook.net"/>
<generator uri="https://www.getzola.org/">Zola</generator>
<updated>2024-10-03T00:00:00+00:00</updated>
<id>https://lockbook.net/atom.xml</id>
<entry xml:lang="en">
<title>OpSec FAQ</title>
<published>2024-10-03T00:00:00+00:00</published>
<updated>2024-10-03T00:00:00+00:00</updated>
<author>
<name>Unknown</name>
</author>
<link rel="alternate" type="text/html" href="https://lockbook.net/blog/opsec-faq/"/>
<id>https://lockbook.net/blog/opsec-faq/</id>
<content type="html" xml:base="https://lockbook.net/blog/opsec-faq/"><h1 id="what-does-secure-mean">What does secure mean?</h1>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16b81878-96c9-4e65-bc75-e88c829a572a_1604x716.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16b81878-96c9-4e65-bc75-e88c829a572a_1604x716.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>We call <a rel="external" href="https://blog.lockbook.net/cp/136569024">Lockbook</a> a secure product. This isn't a unique claim to make as you can see below.</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc953a99c-81ef-4325-9690-687e0ac4e26b_1202x1042.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc953a99c-81ef-4325-9690-687e0ac4e26b_1202x1042.png" alt="" loading="lazy" decoding="async" /></a></p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb8991a-aedb-4244-b958-8a689882b9fc_872x444.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cb8991a-aedb-4244-b958-8a689882b9fc_872x444.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>So what's the difference between Notion's claim and ours? It's simple, we can't see your notes even if we wanted to, and Notion can. There may be policies, protections, and certifications to ensure they don't do anything <em>improper</em> with your data, but they have the <em>ability</em> to see your content. In contrast, we don't have that ability.</p>
<p>Before your content departs from your device it's <em>encrypted</em> in such a way that only you or any collaborators you chose can <em>decrypt</em> the data. Our server never receives the decryption keys so we can't spy on you, our hosting provider can't spy on you and the government can't spy on you. This is called <a rel="external" href="https://en.wikipedia.org/wiki/End-to-end_encryption">end-to-end encryption</a>. You can learn more about this <a rel="external" href="https://www.youtube.com/watch?v=jkV1KEJGKRA">here</a>.</p>
<h1 id="how-do-i-know-i-can-trust-lockbook">How do I know I can trust Lockbook?</h1>
<p>Because we don't believe in <a rel="external" href="https://en.wikipedia.org/wiki/Security_through_obscurity">security through obscurity</a>, all of our code is <a rel="external" href="https://github.com/lockbook/lockbook">open source</a>. We want to make it as easy as possible for someone to audit our code. All of the code that would be relevant to an audit is written in a single language and relies on well-established cryptographic primitives like <a rel="external" href="https://www.youtube.com/watch?v=NF1pwjL9-DE">eliptic curve cryptography</a> and <a rel="external" href="https://www.youtube.com/watch?v=O4xNJsjtN6E">AES</a>.</p>
<p>The keen-eyed among us ask: how do we know you're running and shipping the code that's on GitHub? You don't, but we engineered lockbook so that the app running on your phone (the client) doesn't trust our server either. It doesn't send any secrets and verifies (cryptographically) the information it receives.</p>
<p>To be frank -- we don't trust our server either! We consider our cloud infrastructure to be an adversarial environment and have engineered the whole product to be resilient to snooping and unexpected downtime. This is part of the reason we placed such a great emphasis on offline support. Long term we envision a decentralized future (much like the email protocol), but that's a daydream for the time being.</p>
<p>For your convenience, we build and publish our apps to a variety of marketplaces of varying trustworthiness (like Apple's App Store). But we've also made it as easy as possible for you to build any of our apps directly from source to cut out all the middlemen -- allowing you to be absolutely certainty that you're running the code you expect.</p>
<h1 id="why-should-i-care-if-google-can-see-my-content">Why should I care if Google can see my content?</h1>
<p>Some people are shocked to find out that most companies can just see all your content.</p>
<p>Others don't really care if some select group of people have access to their documents. They don't fear the government because they don't think they are or ever will be a target (I hope they're right).</p>
<p>Despite this, they still don't want their friends, families, or enemies to see their content. It's private and they'd like to keep it that way.</p>
<p>Companies, however, <a rel="external" href="https://en.wikipedia.org/wiki/List_of_data_breaches">get </a><strong><a rel="external" href="https://en.wikipedia.org/wiki/List_of_data_breaches">hacked</a></strong><a rel="external" href="https://en.wikipedia.org/wiki/List_of_data_breaches"> all the time</a>. They leak passwords emails, and content <strong>all the time</strong>. The perpetrator could be anyone from a foreign government to a talented prepubescent basement dweller. It could be a disgruntled employee or a misconfigured database. When the data sitting on the server is compromised do you want it to be a garbled mess of encrypted data, or do you want it to be every photo you've taken in the last 15 years?</p>
<h1 id="so-is-my-lockbook-unhackable">So is my Lockbook unhackable?</h1>
<p>A useful mental model for determining how secure you are is something like "How much would it cost to compromise me?".</p>
<p>To compromise most traditional companies the exploit may be as simple as waiting for an employee to make a mistake and expose secrets. If that doesn't work an attacker could explore bribing an employee or even infiltrating the company.</p>
<p>Because the data sitting on our server is encrypted, for someone to gain access to your content they have to compromise your individual device. Hacking into an individual's device is several orders of magnitude more expensive. Apple is willing to pay up to <a rel="external" href="https://security.apple.com/bounty/categories/">$2M bounties</a> for certain types of device compromises. Widescale compromises of devices like the iPhone are far more rare than the compromises of online services.</p>
<p>Often with these types of compromise physical access is required. So if someone wants to get your content they may need to hire a thief to break into your home, and then use an exploit that may be worth millions of dollars.</p>
<p>Additionally, Lockbook goes to some lengths to make sure you don't compromise yourself. We generate a key for you with 256 bits of entropy (a very long unguessable password). This means you can't accidentally re-use a password and compromise yourself.</p>
<p>This is an irrecoverable key eliminating the chance of an <a rel="external" href="https://medium.com/@CodyBrown/how-to-lose-8k-worth-of-bitcoin-in-15-minutes-with-verizon-and-coinbase-com-ba75fb8d0bac">email or phone compromise</a> additionally compromising your Lockbook.</p>
<p>You're not, however uncompromisable. There is a strong element of personal responsibility when it comes to security. If you're out there downloading random <code>cracked-photoshop.exe</code>s much of your protection goes out the window.</p>
<p>Security is a chain, and attackers will seek to exploit the weakest (cheapest) link in your setup.</p>
<h1 id="how-do-i-use-lockbook-securely">How do I use Lockbook Securely?</h1>
<p>The design of Lockbook makes your content as secure as your devices are. Here are some very broad general recommendations for how I think about security.</p>
<h2 id="mobile-devices">Mobile Devices</h2>
<p>Mobile devices are generally inherently secure devices. Apps are running in a very limited execution environment and can't access each other's data. Use popular devices, keep them fresher for ~4 years, update your software, and use the security features your phone ships with (1111 is not a good passcode). If you do all this, you're at a pretty strong starting point.</p>
<p>As I mentioned above it takes a fair amount of sophistication for someone to break into an iPhone that's up to date. Your local police department can't do it, and probably not all of the 3 letter federal agencies can (but a few probably can). I think it's probably best to consider big tech and government synonymous from an adversarial perspective.</p>
<p>Google has some incredibly strong incentives to spy on you. They don't make the slightest effort to implement end-to-end encryption in their messengers and often they send computations to a server that Apple performs locally. Apple is incentivized to sell devices not ads, Apple has formed a reputation for simplicity and security.</p>
<p>Apple rules the app store supply chain with an iron fist which introduces attack vectors for supply chain attacks and censorship.</p>
<p>Both iOS and Android have open-source roots but neither of these platforms are practically open source. Both platforms have huge amounts of unremovable infrastructure that is closed source.</p>
<p>There are, however, secure phone implementations like Graphene, Librem, Liberty, and the Pinephone. The theme is generally: reasonably secure hardware and fully open-source software. Configured by default to make it easier to use securely and privately.</p>
<p>There is a school of thought that says phones are unsecurable. It's just too hard to have a cell plan that isn't coarsely tracking you with cell tower metadata. This way of thinking also considers phones to be toxic machines of addiction and control and recommends using dumb phones or no phones at all.</p>
<h2 id="computers">Computers</h2>
<p>The surface area of attack on computers is far broader and we depend on computers for essential activities.</p>
<p>The security situation on Windows is a bit of a disaster, many Windows computers come pre-packaged with a <a rel="external" href="https://arstechnica.com/gaming/2015/05/humanity-weeps-as-candy-crush-saga-comes-pre-installed-with-windows-10/">large amount of bloatware</a>. This increases the surface area of attack for devices. Windows is a fragmented ecosystem so suggestions to "only install <em>sandboxed</em> apps from the Microsoft Store" are effectively impractical. The normal way to install and update things is to <em>download an exe from a website</em> , a pretty bad security default.</p>
<p>In my opinion, Macbooks are a step up in security from Windows. Things on macOS are closer to iPhones, by default, the installation comes with minimal bloat and the security defaults are reasonable. Apps have to ask permission to access various resources. Additionally, you can turn off some security features and download apps from arbitrary locations. However, both Windows and macOS are largely closed source leaving room for "bugs" and backdoors.</p>
<p>The next step up here would be to run an open-source Linux flavor on commonly available hardware (Thinkpads, Dell laptops, or a Desktop computer). "Distributions" like Ubuntu, Fedora, and Manjaro provide a gentle introduction to Linux. These days the transition may be easier than you'd expect as most computing can happen in the browser.</p>
<p>This is a pretty solid place to arrive. Most of what you're running is open source and inherently more secure. You'll likely install and update all your software through your distro's package manager, either graphically or through the command line.</p>
<p>From here our next stop is minimal, hand-crafted Linux distros. On distros like Arch, and Gentoo you gain an understanding of what all the moving pieces of your computer are, and you play an active role in their assembly. Once you're setup you have a strong understanding of everything that's running on your system. What's running on your system is likely just what you need, and nothing you don't. This means your surface area for attack is as small as possible. At this step, you're probably already familiar with command line interfaces, and can likely use the <em>Lockbook CLI</em> rather than the desktop version -- further reducing the surface area of attack.</p>
<p>At this stage you may also consider exploring the BSD variants (historically more secure kernel than Linux), and specialized operating systems like QubesOS / Tails. You may also consider specialized hardware that seeks to remove eyebrow-raising hardware components like the <a rel="external" href="https://www.youtube.com/watch?v=HNwWQ9zGT-8">Intel Management Engine</a>.</p>
<h2 id="physical-security">Physical Security</h2>
<p>It's also worth noting that there are very few software solutions to the wrench attack:</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50549fd7-8719-4ae1-a3fa-d4fd2bca53c8_448x274.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50549fd7-8719-4ae1-a3fa-d4fd2bca53c8_448x274.png" alt="Security" loading="lazy" decoding="async" /></a></p>
<p>If your secrets are <a rel="external" href="https://github.com/jlopp/physical-bitcoin-attacks/blob/master/README.md">valuable enough</a> to guard, consider investing in some <a rel="external" href="https://en.wikipedia.org/wiki/Second_Amendment_to_the_United_States_Constitution">real</a> <a rel="external" href="https://blog.casa.io/a-home-defense-primer/">physical security</a>. Understand that your adversaries may be immoral actors who will happily kidnap your family members to make you do what they want.</p>
<h1 id="is-lockbook-secure-enough-for-me">Is Lockbook secure enough for me?</h1>
<p>Lockbook is a young piece of software, and as such may contain bugs. We believe we're secure by design, we've designed everything around making sure that you'll never leak information because of a bug. Rather our worst bugs should be crashes, missing documents, or the inability to communicate with our server. We do believe we're in a fundamentally different category of security than products that aren't end-to-end encrypted and open source and you are better off using us compared to those solutions.</p>
<p>But if your life literally depends on the security of your technology there's no avoiding dramatically investing a thorough knowledge of security and evaluating your chosen solution (lockbook, signal, PGP, local-only solutions, literally not using technology) at a very deep and fundamental level.</p>
<h1 id="how-do-i-learn-more-about-security">How do I learn more about security?</h1>
<p>Here are some resources I've found valuable for better understanding the world of security:</p>
<ul>
<li>
<p><a rel="external" href="https://www.youtube.com/@MentalOutlaw">YT: MentalOutlaw</a></p>
<ul>
<li>
<p>OpSec news</p>
</li>
<li>
<p>Analysis of how various people have been compromised</p>
</li>
<li>
<p>Instruction for higher security setups</p>
</li>
</ul>
</li>
<li>
<p><a rel="external" href="https://open.spotify.com/show/4XPl3uEEL9hvqMkoZrzbx5">Podcast: Darknet Diaries</a></p>
<ul>
<li>Interviews of hackers, spies, and an exploration of hacking culture</li>
</ul>
</li>
<li>
<p><a rel="external" href="https://www.lopp.net/articles.html">Blog: Jameson Lopp</a></p>
<ul>
<li>Crypto-focused OpSec discussion</li>
</ul>
</li>
<li>
<p><a rel="external" href="https://bigtech.fail/">Blog: bigtech.fail</a></p>
<ul>
<li>"Shining a light on the censorship, propaganda, and mass surveillance from today's tech corporations and governments."</li>
</ul>
</li>
<li>
<p><a rel="external" href="https://www.youtube.com/@LowLevelLearning">YT: Low Level</a></p>
<ul>
<li>Technical analysis of high-profile security vulnerabilities</li>
</ul>
</li>
</ul>
</content>
</entry>
<entry xml:lang="en">
<title>Migrating Lockbook to a Better Key Format</title>
<published>2024-09-09T00:00:00+00:00</published>
<updated>2024-09-09T00:00:00+00:00</updated>
<author>
<name>Unknown</name>
</author>
<link rel="alternate" type="text/html" href="https://lockbook.net/blog/migrating-lockbook-to-a-better-key/"/>
<id>https://lockbook.net/blog/migrating-lockbook-to-a-better-key/</id>
<content type="html" xml:base="https://lockbook.net/blog/migrating-lockbook-to-a-better-key/"><p>On Lockbook, creating an account is simple. You choose a username, and Lockbook will generate an account key. This is what it looks like:</p>
<pre><code>CwAAAAAAAABzbWFpbHRlc3RzMR0AAAAAAAAAaHR0cHM6Ly9hcGkucHJvZC5sb2NrYm9vay5uZXQgAAAAAAAAAJ/1ORmw56YptpNdQvJmGNsE1Lh4qpyYxRl6pp5dE7z0
</code></pre>
<p>This key is the only thing you need to access your files on your device. You don't even need to remember your username. And besides, creating your own password is always less secure. Most people reuse passwords from other accounts or use weak passwords. But with a generated account key, Lockbook keeps your notes safe and secure against attacks like <a rel="external" href="https://en.wikipedia.org/wiki/Credential_stuffing">credential stuffing</a> and <a rel="external" href="https://en.wikipedia.org/wiki/Dictionary_attack">dictionary attacks</a>.</p>
<p>The account key is a critical part of our <a rel="external" href="https://en.wikipedia.org/wiki/End-to-end_encryption">end-to-end encryption scheme</a>. This ensures that no one besides you can see your notes, not even us. This account key corresponds to a private key <a rel="external" href="https://en.bitcoin.it/wiki/Secp256k1">from the </a><code>secp256k1</code> encryption standard. A user's files are encrypted hierarchically <a rel="external" href="https://en.wikipedia.org/wiki/Advanced_Encryption_Standard">using </a><code>AES</code>, another encryption standard, and the uppermost key is encrypted using the public key corresponding to your private key. This is called hybrid encryption, and it combines the benefits of both symmetric and asymmetric encryption capabilities. You can read more about it <a rel="external" href="https://en.wikipedia.org/wiki/Hybrid_cryptosystem">here</a>.</p>
<p>Our current account key has some issues though. It contains unnecessary information, like what server your Lockbook communicates to, and the username. All of which is <a rel="external" href="https://en.wikipedia.org/wiki/Base64">Base64 encoded</a>, resulting in a combination of random characters. This isn't necessarily bad, but for someone who might want to write their account key down, it is difficult and error prone. It reminds me of an xkcd comic:</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50192293-c310-4ef7-9963-928b3b032e80_1480x1202.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50192293-c310-4ef7-9963-928b3b032e80_1480x1202.png" alt="" loading="lazy" decoding="async" /></a></p>
<h2 id="passphrases">Passphrases</h2>
<p>To solve this issue we took some inspiration from Bitcoin since they use the same private keys. <a rel="external" href="https://en.bitcoin.it/wiki/BIP_0039">BIP (Bitcoin Improvement Proposal) 39</a> described a way to turn bytes into a mnemonic phrase. Every combination of 11 bits corresponded to a unique word. The motivation was that words are harder to input incorrectly than random characters, and this is exactly what we need. In addition, these words were specifically chosen to be simple. Here's what it looks like:</p>
<pre><code>turkey, era, velvet, detail, prison, income, dose, royal, fever, truly, unique, couple, party, example, piece, art, leaf, follow, rose, access, vacant, gather, wasp, audit
</code></pre>
<p>Another aspect of this proposal was the inclusion of a checksum, which added a self-verifying mechanism to ensure that a phrase has been entered correctly. Since Lockbook uses 256-bit private keys with an additional 4 bits for the checksum, the total key length is 260 bits. This corresponds to a word count of 24 words. This is great and solves the writing issue we discussed before.</p>
<p>But sometimes users still want a compact key; like for a QR code or for a password manager. Our previous key had its advantages, and we can reduce its size by removing the username and server URL. This effectively halves the number of characters. It looks something like this:</p>
<pre><code>nvo7SItwXYmoxxzmOCUrNJiw85V8CwJ+SXb8cOHPIlo=
</code></pre>
<p>So, when you enter your settings, you have two choices. You can export your phrase or a compact version of your account key. Either will work across all your devices.</p>
<h2 id="migration">Migration</h2>
<p>Changing private keys is hard. If we just updated our code to use the new keys in the next release, people would have issues logging in. Additionally, some users may have the old account key saved in password managers, and it would be unacceptable if users couldn't sign in after returning to Lockbook.</p>
<p>As a result, because we take breaking changes very seriously, we decided to support the previous key format indefinitely. Once most users are on the new version, we will switch to using the new key format. Minimizing the risk of someone using a new key with an incompatible app. We'll also communicate this change across all our social media platforms.</p>
<h2 id="coding">Coding</h2>
<p>The majority of the business logic in our apps is written in Rust. This is thanks to <code>lb-rs</code>, <a rel="external" href="https://blog.lockbook.net/cp/136569912">a shared library we use</a> to iterate quickly across our platforms. This is where I wrote the new key logic. I started by importing a <a rel="external" href="https://github.com/vincenthz/bip39-dict/">library called </a><code>bip39-dict</code>, which provided the binary-to-word translations. In BIP 39, every 11 bits corresponded to a word, so I had to split up the <code>Vec&lt;u8&gt;</code> private key into 11-bit chunks. The implementation was simple. After implementing a method to convert the private key into a phrase, I made a method to turn the phrase into a private key. This simply involved turning each word it into a <code>u16</code>, and converting chunks of <code>u16</code>s (considering only the first 11 bits) into <code>u8</code>s. I added some tests to verify the inverse properties of these two functions. More details on my efforts can be found <a rel="external" href="https://github.com/lockbook/lockbook/pull/2811">here</a>.</p>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>With these updates in place, we're excited to continue improving Lockbook. As a unique open-source project, Lockbook has a myriad of interesting problems. If you're interested in contributing, feel free to check out the <a rel="external" href="https://github.com/lockbook/lockbook/">GitHub</a> and join our <a rel="external" href="https://discord.com/invite/lockbook">Discord</a>. We would love to have you.</p>
</content>
</entry>
<entry xml:lang="en">
<title>Multimedia Updates!</title>
<published>2024-07-06T00:00:00+00:00</published>
<updated>2024-07-06T00:00:00+00:00</updated>
<author>
<name>Unknown</name>
</author>
<link rel="alternate" type="text/html" href="https://lockbook.net/blog/multimedia-updates/"/>
<id>https://lockbook.net/blog/multimedia-updates/</id>
<content type="html" xml:base="https://lockbook.net/blog/multimedia-updates/"><p>In a few videos we've expressed that we've been focusing on building up our infrastructure to better support <a rel="external" href="https://www.youtube.com/watch?v=5w-kDNu5rz0">multimedia</a> and increase overall platform stability. Today I'd like to share some exciting updates on the multimedia front!</p>
<h2 id="lockbook-workspace">Lockbook Workspace</h2>
<p>In a previous post, we shared details about our <a rel="external" href="https://blog.lockbook.net/cp/136569994">cross-platform markdown editor</a>, which allowed us to increase the complexity and interactivity of our editor. After working out the kinks with the initial implementation we've doubled down on this strategy and expanded it to the entire tab strip and all content displayed within Lockbook. We call this component the <em>Lockbook Workspace</em>. As a portion of the team brought workspace to all of the platforms, Adam redesigned our drawing experience from the ground up to use SVGs instead of a proprietary drawing format. <strong>Canvas</strong> deserves its own post, so stay tuned for that. In addition to SVGs and Markdown, workspace brought image and PDF previews to all platforms.</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff16e346f-be0a-4731-bdcb-9ba4c3625654_2598x1754.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff16e346f-be0a-4731-bdcb-9ba4c3625654_2598x1754.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>Markdown and SVG have crystalized as the 2 main document formats that will be editable inside Lockbook. These open formats are a natural fit for our customer-centric values. They both offer broad compatibility across the internet and don't lock you into our platform. The freeform expression of SVGs complements the restricted feature set of Markdown nicely. SVGs are also trivially embedded inside markdown documents as images.</p>
<p>Supporting these two document types offers our platform access to two very diverse types of note-takers. On one hand, there's the sort of people who like apps like OneNote, Notability, and GoodNotes for their unstructured creative surface. On the other hand, some people like the structure of apps like Notion, Obsidian, and Google Docs for their searchable, linkable, and collaborative experience.</p>
<p>A key idea of our platform is to not split your life among different apps all fundamentally storing bytes for you and your team. My co-founder Travis and I are members of both of these modalities. Users like my Dad are heavy OneNote users, while there are plenty of users who are pretty firmly in the "strongly typed" category of markdown.</p>
<h2 id="lockbook-filesystem">Lockbook Filesystem</h2>
<p>When we were making early design decisions for Lockbook's system architecture, we considered the many ways we could allow our users to organize their thoughts. We considered a tag-like system similar to Bear that optimizes for flexibility (a note could live in two folders at once). We also considered a Google Keep-like single-note experience. But I strongly advocated for a "Files and Folders" hierarchy. I knew I wanted Lockbook to integrate deep into the traditional computing experience seamlessly. There are times when you want to edit Markdown using our fancy Markdown editor. And there are times when you want to edit spreadsheets and photos and have all the durability and security guarantees of Lockbook. Again the key idea here is to not split your life across various apps, we don't want you to have to use Google Drive / DropBox for one type of content and Lockbook for another.</p>
<p>As Lockbook emerges out of its state of running an ungodly amount of experiments, this was another area I wanted to de-risk and see how our platform and infrastructure performed. Tax season was also approaching and we had similarly flavored requests from people who wanted to use the types of apps we're never going to be in the business of creating.</p>
<p>We <em>somewhat supported</em> the basic workflow of dropping files in and out of Lockbook. But this is clunky and our users expect more from our ragtag crew of part-time developers. So I took a long weekend and tried to determine if we could do better.</p>
<p>The first thing that came to mind was to use the <a rel="external" href="https://en.wikipedia.org/wiki/Filesystem_in_Userspace">FUSE</a> protocol. This would allow our users to seamlessly <strong>mount</strong> their Lockbook as if it's a flash drive on their computer. Any requests for bytes would be fielded directly by the Lockbook instance running on your computer and we don't need to be in the business of watching directories for changes and trying to reconcile changes. This was our target UX but unfortunately, FUSE only works well on Linux, and on macOS users would have to install some pretty invasive 3rd party software.</p>
<p>A close second flavor of the same thing is the <a rel="external" href="https://en.wikipedia.org/wiki/Network_File_System">NFS</a> protocol. Offering a similar experience to FUSE, with some additional baggage associated with the network. Fortunately, this works pretty seamlessly on both macOS and Linux. I stumbled upon an <a rel="external" href="https://github.com/xetdata/nfsserve">NFS-Server</a> crate which made prototyping a very productive experience.</p>
<p>In a couple of days, I had a high-performance implementation ready. Mounting my whole Lockbook directory and seeing it work effortlessly with Lightroom, Keynote, and CAD software was a pretty magical moment for me as an engineer.</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb03f860f-f925-488d-bc35-f9ddc8883d0a_1908x1266.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb03f860f-f925-488d-bc35-f9ddc8883d0a_1908x1266.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>We shipped an early preview of lb_fs in our <code>CLI</code> in 0.9.0. So far we've experienced some good feedback. We even had one of our users use the filesystem as part of an <a rel="external" href="https://coreycc.com/md/blog/backup-dotfiles-with-lockbook.md">automation pipeline</a> for their dotfiles!</p>
<p>We're excited about the future of lb-fs. We intend to integrate it directly into our desktop apps -- allowing you to click on any document not supported by Workspace and open it natively on your computer. We also want you to be able to click any folder and "Open Externally". Allowing you to seamlessly backup the decrypted contents as easily as copying them to a different location on your computer.</p>
<p>But at the moment we're pausing for some reflection: should lbfs continue investing in NFS? On Windows, it requires Windows Pro (which most users don't have, and there is no 3rd party stopgap). Potentially, we could seek a higher quality platform-specific interface like <a rel="external" href="https://learn.microsoft.com/en-us/windows/win32/projfs/projected-file-system">ProjFS</a>. If we were to explore something like that on macOS we could add nice touches like showing the sync status or collaboration details within Finder itself.</p>
<p>This could also be a cool opportunity to create a state-of-the-art, cross-platform virtual file system abstraction for the Rust ecosystem. If you'd be interested in pursuing something like that please <a rel="external" href="https://discord.gg/lockbook">join our Discord</a> and reach out! We'd be happy to support you in any way we can.</p>
<h2 id="other-infrastructural-updates">Other Infrastructural updates</h2>
<p>Further investments in multimedia right now are bottlenecked by our current networking implementation. We expect it to be a small lift to unlock the potential of ws and fs by using a slightly more sophisticated approach to networking:</p>
<ul>
<li>
<p>don't sync all your files all the time -- don't sync large files to my iPhone, let me log in immediately and lazily fetch files as needed (still have a well-managed cache for great offline support).</p>
</li>
<li>
<p>be able to more reliably sync large files -- presently, especially under adverse network circumstances, large files are particularly problematic.</p>
</li>
<li>
<p>fetch and push files in parallel.</p>
</li>
</ul>
<p>These features and a few others comprise our <a rel="external" href="https://github.com/lockbook/lockbook/issues/2214">Sync 4.0 tracker</a>, the product of which has significant implications for everything mentioned above. Sync 4.0 should also allow us to sync way more aggressively (where appropriate) -- a long-standing request from almost every type of user.</p>
<p>Once we have this situation under control we can start to look toward a future where we have a richer set of tools for collaboration:</p>
<ul>
<li>
<p>document revisions</p>
</li>
<li>
<p>document comments</p>
</li>
<li>
<p>author history (like git blame)</p>
</li>
<li>
<p>dare I say -- Google Docs style real-time collaborative editing?</p>
</li>
</ul>
<p>These features will likely be presented in workspace itself, but will be present for all file types fundamentally.</p>
<p>You can track the broader multimedia efforts <a rel="external" href="https://github.com/lockbook/lockbook/issues/1947">here</a>.</p>
<p>If you have a specific use case that we didn't cover above we'd love to hear from you! <a rel="external" href="https://discord.gg/lockbook">Join our Discord</a> and share your thoughts!</p>
<h2 id="footnote-community-document-types">Footnote: Community Document Types</h2>
<p>Another interesting opportunity that workspace presents our community is the ability to author custom new document types. If you can come up with a data format, and write an <a rel="external" href="https://github.com/emilk/egui">egui</a> widget then you can contribute a new file type to Lockbook workspace.</p>
<p>Presently we have some community members pursuing interesting visualizations of disk space and links within markdown documents inspired by <em>Disk Usage Analyzer</em> on Linux and the <em><a rel="external" href="https://help.obsidian.md/Plugins/Graph+view">Obsidian Graph View</a></em>.</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11fb7816-0c6b-4f6f-9e73-6b8a258b5f36_957x625.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11fb7816-0c6b-4f6f-9e73-6b8a258b5f36_957x625.png" alt="" loading="lazy" decoding="async" /></a></p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F678cce90-3b8d-44cf-97f6-be5050e36f03_1199x980.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F678cce90-3b8d-44cf-97f6-be5050e36f03_1199x980.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>We've also heard lots of interesting ideas about building habit trackers and to-do lists this way as well. If you're interested in whipping up something like this <a rel="external" href="https://discord.gg/lockbook">join our Discord!</a> For now, we will play an active role in what file types make it to all users, but one day this structure may grow into a formal plugin system!</p>
</content>
</entry>
<entry xml:lang="en">
<title>Lockbook 0.9 🚀</title>
<published>2024-03-02T00:00:00+00:00</published>
<updated>2024-03-02T00:00:00+00:00</updated>
<author>
<name>Unknown</name>
</author>
<link rel="alternate" type="text/html" href="https://lockbook.net/blog/lockbook-09/"/>
<id>https://lockbook.net/blog/lockbook-09/</id>
<content type="html" xml:base="https://lockbook.net/blog/lockbook-09/"><p>Lockbook 0.9 ships with progress on 4 fronts:</p>
<ul>
<li>
<p><em>Lockbook Workspace</em> comes to iOS, bringing pdf, image and other multimedia to iPhones and iPads.</p>
</li>
<li>
<p>Lockbook’s CLI now ships with <em>lb-fs</em> an experimental mounted file system which allows you edit files in your Lockbook using any applications on your computer.</p>
</li>
<li>
<p>Lockbook’s Drawing Experience: <em>Canvas</em> now features support for images, expanding the type of unstructured notes you can take.</p>
</li>
<li>
<p><a rel="external" href="https://github.com/lockbook/lockbook/releases/tag/0.9.0">A long list of bug fixes and refinements.</a></p>
</li>
</ul>
<p>If you’d like to hear more about this release from our team checkout our latest video:</p>
<p>As always we’d love to hear from you about what you like and what you don’t like. Don’t hesitate to join the conversation on Discord: <a rel="external" href="https://discord.gg/lockbook">https://discord.gg/lockbook</a></p>
</content>
</entry>
<entry xml:lang="en">
<title>Creating a sick CLI</title>
<published>2023-10-11T00:00:00+00:00</published>
<updated>2023-10-11T00:00:00+00:00</updated>
<author>
<name>Unknown</name>
</author>
<link rel="alternate" type="text/html" href="https://lockbook.net/blog/creating-a-sick-cli/"/>
<id>https://lockbook.net/blog/creating-a-sick-cli/</id>
<content type="html" xml:base="https://lockbook.net/blog/creating-a-sick-cli/"><p>At <a rel="external" href="https://parth.cafe/p/introducing-lockbook">Lockbook</a> we strongly believe in <a rel="external" href="https://en.wikipedia.org/wiki/Eating_your_own_dog_food">dogfooding</a>. So we knew alongside a great, native, markdown editing experience we would want a <em>sick</em> CLI. Having a <em>sick</em> CLI creates interesting opportunities for a niche type of user who is familiar with a terminal environment:</p>
<ul>
<li>
<p>They can use the text editor they're deeply familiar with.</p>
</li>
<li>
<p>They can write scripts against their Lockbook.</p>
</li>
<li>
<p>They can vastly reduce the surface area of attack.</p>
</li>
<li>
<p>Can always maintain remote access to their Lockbook via SSH.</p>
</li>
</ul>
<p>In this post I’m going to tackle 3 topics:</p>
<ol>
<li>
<p>What makes a CLI sick?</p>
</li>
<li>
<p>How do you go about realizing some of those “interesting opportunities” using our CLI?</p>
</li>
<li>
<p>What’s next for our CLI?</p>
</li>
</ol>
<h1 id="what-makes-a-cli-sick">What makes a CLI <em>sick</em>?</h1>
<p>It’s tab completions. For me, tab completions are what I use to initially explore what a CLI can do. Later, if the CLI is <em>sick</em> , I use tab completions to speed up my workflow. I don’t just want to tab complete the structure of the CLI (subcommands and flags). I want to tab complete dynamic values, in Lockbook's case, this means completing file paths and IDs.</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F520d4b31-50c4-4c07-8e35-38b1bcb2f3d6_946x374.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F520d4b31-50c4-4c07-8e35-38b1bcb2f3d6_946x374.png" alt="" loading="lazy" decoding="async" /></a></p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77563e15-d3ac-4e85-84b1-27c341b598f0_1034x370.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77563e15-d3ac-4e85-84b1-27c341b598f0_1034x370.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>If you're creating a CLI most libraries make you choose between a few bad options:</p>
<ul>
<li>
<p>Hand-craft completion files for each shell.</p>
</li>
<li>
<p>Sacrifice dynamic completions and just settle for automatically generated static completions.</p>
</li>
</ul>
<p>Rust is no exception here, <code>clap</code> has some support for static completions, but no way to invoke dynamic completions without writing a completion file for each shell.</p>
<p>And so we set out to solve this problem for the Rust ecosystem, and created <code>cli-rs</code>. A parsing library, similar to <code>clap</code> but with explicit design priorities around creating a great tab completion experience. As soon as <code>cli-rs</code> was stable enough we re-wrote <code>lockbook</code>'s CLI using it so we could pass on these gains to our users</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cebb737-4276-46df-a78f-316541b49aac_1266x952.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cebb737-4276-46df-a78f-316541b49aac_1266x952.png" alt="" loading="lazy" decoding="async" /></a></p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd281cadb-328d-4495-ad53-727caef8bdd1_1022x320.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd281cadb-328d-4495-ad53-727caef8bdd1_1022x320.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>Cli-rs is simple, you describe your CLI like this:</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17154cfe-9918-4f99-a460-20838e1bb009_1346x640.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17154cfe-9918-4f99-a460-20838e1bb009_1346x640.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>This gives the parser all the information it needs to offer the best tab completion behavior. It handles all the static completions internally and then invokes your program when it’s time to dynamically populate a field with your user’s data.</p>
<p>We also invested a ton of effort in the infrastructure that deploys our CLI to our customer's machines so that tab completions would be set up for most people by default.</p>
<h1 id="exciting-opportunities-for-power-users">Exciting Opportunities for Power Users</h1>
<h2 id="use-your-favorite-text-editor">Use your favorite text editor</h2>
<p>You can <code>lockbook edit</code> any path you have access to and our CLI will invoke <code>vim</code>, utilizing any custom <code>.vimrc</code> that may exist. You can override the selected editor by setting the <code>LOCKBOOK_EDITOR</code> env var or using the <code>--editor</code> flag. So far we support <code>vim</code>, <code>nvim</code>, <code>subl</code>, <code>code</code>, <code>emacs</code> and <code>nano</code>.</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf94e90e-2daa-4f44-ac88-69c71d50a4e3_1266x952.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf94e90e-2daa-4f44-ac88-69c71d50a4e3_1266x952.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>If we don’t support your favorite editor, send us a PR or hop in our <a rel="external" href="https://markdowntohtml.com/TODO">discord</a> and tell us.</p>
<h2 id="extending-lockbook">Extending Lockbook</h2>
<p>We want Lockbook to be maximally extensible, this extensibility will take many forms, one of which is our CLI. Let's explore some of the interesting things you can accomplish with our CLI.</p>
<p>Let’s say you wanted a snapshot of everything in your second brain decrypted and without any proprietary format for tin-foil-hat backup reasons. You can easily set a <code>cron</code> that will simply <code>lockbook sync</code> and <code>lockbook backup</code> however often you want. <code>lockbook export</code> can be used to write any folder or document from Lockbook to your file system, paving the way for automated updates of a blog. Edit a note on your phone, and see the change live on your blog in seconds. <code>lockbook import</code> lets you do the opposite. Want to continuously back up a folder from your computer to Lockbook? Setup a <code>cron</code> that will simply <code>Lockbook import</code> and then <code>lockbook sync</code>.</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3227172c-f7b8-4412-a5eb-a7ebc742b224_924x416.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3227172c-f7b8-4412-a5eb-a7ebc742b224_924x416.png" alt="" loading="lazy" decoding="async" /></a></p>
<h2 id="ultra-secure">Ultra secure</h2>
<p>I like to think about security as the product of a few numbers. So if, for example, you’re product is closed source, one of those numbers in your multiplication chain is a big fat zero. And there’s nothing you can do to pretend it’s secure. Similarly, the age of a product is one of those numbers. Newer is worse, and this is one of Lockbook’s current weaknesses.</p>
<p>But one of Lockbook’s strengths is how much you can reduce the total amount of code it takes to interact with Lockbook. On one end of the spectrum, you have software that <strong>requires</strong> a full browser installation to perform the most basic tasks. Slightly better than that is software that runs natively, and on the other end of the spectrum is software that doesn’t even rely on a UI library. This is where our CLI comes into play: if you wanted to run Lockbook on a libre-booted Thinkpad running an ultra-minimal operating system, Lockbook wouldn’t require you to add the Google Chrome dependency tree to your setup.</p>
<h2 id="remote-lockbook">Remote Lockbook</h2>
<p>Sometimes you find yourself employed by a financial institution that heavily restricts what you can do on their machines. Without thinking too much more about your situation you may want to simply add something to your grocery list without pulling out your phone. Unfortunately, IT has locked down your remote Windows 7 installation, and not only can you not install our Windows app (which does not require administrator privileges to install) but you cannot visit GitHub itself!</p>
<p>Maybe in this environment, it’s not worth it to update your grocery list, but you identify with the likes of Ron Swanson, and you will not be defeated by your IT department. How? Because you port forwarded your desktop and memorized a lengthy SSH password. So you ssh in, use your favorite text editor, and you update that grocery list. There’s no stopping you.</p>
<h1 id="what-s-next-for-our-cli">What’s next for our CLI</h1>
<p>Our CLI has come a long way, we've experimented with various ways of allowing you to quickly find a note and edit it. In the past we experimented with piping output to programs like <code>fzf</code>, we even tried implementing a custom full-screen search. This is the approach that feels the best to us and we think is going to stand the test of time. But work is never done, so here are some of the things we plan to tackle in our CLI:</p>
<ul>
<li>
<p>Make cli-rs easier for others to use by adding documentation and examples.</p>
</li>
<li>
<p>Continue to invest in our release infrastructure to bring our CLI to more package managers. If you'd like to become a maintainer for a particular distro <a rel="external" href="https://discord.gg/lockbook">reach out!</a>.</p>
</li>
<li>
<p>Support richer parser inputs including variable number of arguments, grouped command line flags, and logical de-duplication of tab completions (this flag or argument is already specified so don't suggest it again).</p>
</li>
<li>
<p>Deeper integrations with shells in <code>cli-rs</code>: offer ways to express that this argument is a normal file with completions, or implement mechanisms to re-write the current prompt (<code>lockbook edit sick&lt;tab&gt;</code> tab completes: <code>lockbook edit writing/parth.cafe/creating-a-sick-cli.md</code> presently tab completion options must begin with the current prompt).</p>
</li>
<li>
<p>A richer showcase of interesting things we can do with our CLI, we plan to set up our blog the way I described above and provide concrete examples of how to do many of the things I outlined. So if you haven't already subscribe to the <a rel="external" href="https://blog.lockbook.net/">Lockbook Blog</a>, and <a rel="external" href="https://www.youtube.com/@lockbook_net">Lockbook Youtube Channel</a>.</p>
</li>
</ul>
</content>
</entry>
<entry xml:lang="en">
<title>Defect Finder</title>
<published>2023-08-24T00:00:00+00:00</published>
<updated>2023-08-24T00:00:00+00:00</updated>
<author>
<name>Unknown</name>
</author>
<link rel="alternate" type="text/html" href="https://lockbook.net/blog/defect-finder/"/>
<id>https://lockbook.net/blog/defect-finder/</id>
<content type="html" xml:base="https://lockbook.net/blog/defect-finder/"><p>When designing <a rel="external" href="https://parth.cafe/p/introducing-lockbook">Lockbook</a> we knew we wanted to support a great offline experience. To our surprise, this grew to become one of the largest areas of complexity. Forming consensus is an active area of research in computer science, but Lockbook has an additional constraint. Unlike our competition, large areas of complexity take place on <a rel="external" href="https://parth.cafe/p/why-lockbook-chose-rust">our user’s devices</a> that can't update remotely. Additionally, the administrative action we can take is limited: most data entered by users is encrypted, and their devices will reject changes that aren’t signed by people they trust. All this is to say that the cost of error is higher for our team and it’ll likely take longer for our software to mature and reach stability. Today I’d like to share a tester we created to help us find defects and accelerate the maturation process. We affectionately called this tester “the fuzzer”. We’ll explore whether this is a good name a bit later, but first, let’s talk about the sorts of problems we’re trying to detect.</p>
<p>Users should be able to do mostly anything offline, so what happens if, say Alice moves a document and Bob renames that document while they were both offline? What happens if they both move a folder? Both edit the same document? What if that document isn’t plain text? What if Alice moves folder B into C, and Bob moves folder C into B at the same time?</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9edec0f4-1955-4626-8c5e-80f3c2822c37_2048x2048.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9edec0f4-1955-4626-8c5e-80f3c2822c37_2048x2048.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>Some of these things can be resolved seamlessly while others may require user intervention. Some of the resolution strategies are complicated and error-prone. The fuzzer ensures regardless of what steps a user (or their device) takes various components of our architecture always remain in a sensible state. Let me share some examples:</p>
<ul>
<li>
<p>Regardless of who moved what files and when, we want to make sure that your file trees never have any cycles.</p>
</li>
<li>
<p>No folder should have two files with the same name. Creating files, renaming files, and moving files could cause two files in a given location to share a name.</p>
</li>
<li>
<p>Actions that change a file's path or sharees could change how our cryptography algorithms search for a file's decryption key, we want to make sure for the total domain of actions your files are always decryptable by you.</p>
</li>
</ul>
<p>As we used our platform we've collected many such <em>validations</em> that we want to ensure never occur for the global set of actions on our platform, and the fuzzer's job is to spit out test cases that violate these constraints. It does this by enumerating all the (significant) actions a user can take on the platform across N devices and with M collaborators. It randomly selects from this space and at each step it asks all parts of our system to make sure everything is still as it should be. It does this process in parallel fully utilizing a given machine's parallel computational resources. It travels through the search space in a manner that limits the amount of recomputation of known good states, fully utilizing a given machine's memory.</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ba1755a-e4ed-46b3-a12a-112f1d635b60_2048x2048.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ba1755a-e4ed-46b3-a12a-112f1d635b60_2048x2048.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>Generally when people say they're <em>fuzzing</em> , they mean handing a user input (like a form field) randomized input to try to produce a failure. Our <em>fuzzer</em> captures that spirit of this but is different enough that plenty of people have raised an eyebrow when I told them we call this process <em>fuzzing</em>. Unfortunately, <strong>Test Simulator</strong> isn't as cool a name. Knowing what this process is now if you can think of a cool name, do tell us.</p>
<p>Today our highly optimized fuzzer executes close to 10,000 of these trials per second, however initially it was just a quick experiment I threw together to gain confidence in an early version of sync. This was written when we were still using an architecture that used <code>docker-compose</code> to spin up <code>nginx</code>, <code>postgres</code>, and <code>pgbouncer</code> locally. The fuzzer almost immediately found some bugs. We fixed these bugs, and the value of the fuzzer was made apparent to us. The time between defects started to grow and so did the intricacies of the bugs the fuzzer revealed. As a background task, we continued to invest in the implementation of the fuzzer, and the hardware it ran on. As our architecture became faster, so did the fuzzer alongside it. Today the fuzzer has been running continuously for months and has verified 10s of billions of user actions, a promising sign as we get ready to begin marketing our product.</p>
<p>Below are some of the fuzzer's key milestones. If you're interested in browsing the most recent implementation you can find it linked <a rel="external" href="https://github.com/lockbook/lockbook/tree/master/libs/core/tests/exhaustive_sync">here</a>.</p>
<h1 id="15-trials-per-second">15 Trials Per Second</h1>
<p>Initially, we were running the fuzzer on our development machines, kicking it off overnight after any large change. Our first big jump in performance came from deciding to run it on a dedicated machine and trying to fully utilize that machine's computational resources.</p>
<h1 id="80-trials-per-second">80 Trials Per Second</h1>
<p>We first tried running our fuzzer on a dedicated server which had 80 vcpus. We purchased <a rel="external" href="https://www.amazon.com/gp/product/B07QQD45Z4/ref=ppx_od_dt_b_asin_title_s00?ie=UTF8&amp;psc=1">this machine</a> for $600 in 2020. Most of our early optimization efforts centered around tuning Postgres to perform better.</p>
<h1 id="250-trials-per-second">250 Trials Per Second</h1>
<p>Our next largest jump in performance was when we made the switch from Postgres to Redis, and upgraded the hardware that the fuzzer runs on. After 2 years of faithful service, our Poweredge experienced a hardware failure which we weren't motivated enough to diagnose. So in 2022 we pooled our resources for a 3990X Threadripper with 120 vCPUs.</p>
<h1 id="900-trials-per-second">900 Trials Per Second</h1>
<p>Before <a rel="external" href="https://parth.cafe/p/db-rs">db-rs</a> there was <a rel="external" href="https://github.com/parth/hmdb">hmdb</a> which was similar in values to db-rs, but worse in execution. It still served our needs better than Redis and performed better as it was embedded in the process rather than something that communicated over the network. It additionally used a vastly more performant serialization protocol across the whole stack, inside [core] and our server.</p>
<h1 id="4000-trials-per-second">4000 Trials Per Second</h1>
<p>In late 2022 I created a compile-time flag in [core] which allowed us to directly compile the entire server into core during test mode. This meant that instead of executing network calls for fetching documents and updates core was directly calling the corresponding server functions. At this point, no part of our test harness was using the network stack.</p>
<h1 id="10-000-trials-per-second">10,000 Trials per second</h1>
<p>Once db-rs was fully integrated into core and server, I added a feature to db-rs called <code>no-io</code>, which allowed core and server to enter a "volatile" mode for testing. This also allowed instances of core, server, and their corresponding databases to be deep copied. So when a trial ran, if most of the trial had been executed by another worker, it would deep copy that trial's state and pick up where it left off.</p>
<h1 id="future-of-the-fuzzer">Future of the fuzzer</h1>
<p>Personally, the fuzzer has been one of the most interesting pieces of software I've worked on. If, like me, this piques your interest and you're interested in researching ways to make it faster with us, <a rel="external" href="https://discord.gg/lockbook">join our discord</a>.</p>
</content>
</entry>
<entry xml:lang="en">
<title>Lockbook's Editor</title>
<published>2023-06-12T00:00:00+00:00</published>
<updated>2023-06-12T00:00:00+00:00</updated>
<author>
<name>Unknown</name>
</author>
<link rel="alternate" type="text/html" href="https://lockbook.net/blog/lockbooks-editor/"/>
<id>https://lockbook.net/blog/lockbooks-editor/</id>
<content type="html" xml:base="https://lockbook.net/blog/lockbooks-editor/"><p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa916acc9-8271-495e-b20c-ae853d06a34f_2000x1500.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa916acc9-8271-495e-b20c-ae853d06a34f_2000x1500.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>As <a rel="external" href="https://parth.cafe/p/introducing-lockbook">Lockbook</a>'s infrastructure stabilized, we began to focus on our markdown editing experience. Across our various platforms, we've experimented with a few approaches for providing our users with an ergonomic way to edit their files. On Android, we use <a rel="external" href="https://github.com/noties/Markwon">Markwon</a>, a community-built markdown editor. On Apple, we initially did the same thing but found that the community components didn't have many of the features our users were asking for. So as a next step, we dove into Apple's <a rel="external" href="https://developer.apple.com/documentation/appkit/textkit">TextKit</a> API to begin work on a more ambitious editor.</p>
<p>Initially, this was fine, but as we worked through our backlog of requests, I found things that were going to be very time-expensive to implement using this API. We were having performance problems when editing large documents. The API was difficult to work with, especially because there were no open existing bodies of work that implemented features like automatic insertion of text (when adding to a list), support for non-text-characters (bullets, checkboxes, inline images), or multiple cursors (real-time collaboration or power user text editing). Even if we did invest the effort to pioneer these features using TextKit, we would have to replicate our efforts on our other platforms. And lastly, none of my other teammates knew the TextKit API intimately, so I wouldn't be able to easily call on their help for one of the most important aspects of our product. We needed a different approach.</p>
<p>In the past, I've discussed our <a rel="external" href="https://parth.cafe/p/why-lockbook-chose-rust">core library</a> -- a place we've been able to solve some of our hardest "backend" problems and bring them to foreign programming environments. We needed something like this for a UI component we needed a place where we could invest the time, build an editor from the ground up, and embed it in any UI library.</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31cca6aa-cf31-4f08-9a9e-f440fb533048_3000x2000.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31cca6aa-cf31-4f08-9a9e-f440fb533048_3000x2000.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>We considered creating a web component. Perhaps we could mitigate some of the downsides of web apps if we were only presenting a web-based view when a document was loaded. Maybe we could leverage Rust's great support for web assembly for the complicated internals. Ultimately I felt like we could do better, so I continued thinking about the problem. On Linux, we'd begun experimenting with <a rel="external" href="https://github.com/emilk/egui">egui</a>: a lightweight, Rust, UI library. Their README had a long list of places you could embed egui, and I wondered if I could add SwiftUI or Android to that list.</p>
<p>And so began my journey of gaining a deeper understanding of <a rel="external" href="https://wgpu.rs/">wgpu</a>, <a rel="external" href="https://eliasnaur.com/blog/immediate-mode-gui-programming">immediate mode UIs</a>, and how this editor might work on mobile devices.</p>
<p>Most UI frameworks have an API for directly interfacing with a lower-level graphics API. In SwiftUI, for instance, you can create an <code>MTKView</code> which gives you access to <a rel="external" href="https://developer.apple.com/documentation/metalkit">MetalKit</a> (Apple's hardware accelerated graphics API). Using this view, you can effectively pass a reference to the GPU into Rust code and initialize an egui component. In the host UI framework you can capture whichever events you need (keyboard &amp; mouse events for instance) and pass them to the embedded UI framework. It's the simplicity of immediate mode programming which enables this to be achievable in a short period, and it's the flexibility of immediate mode programming which makes it a great choice for complex and ambitious UI components. The approach seemed like it held promise so we gave it a go.</p>
<p>After a month of prototyping and pair programming with my co-founder Travis, we had done it. We shipped a version of our Text Editor on macOS, Windows, and Linux which supported many of the features our team and users had been craving. The editor was incredibly high-performance, easily achieving 120fps on massive documents. Most importantly we have a clear picture of how we would go about implementing our most ambitious features over the next couple of years.</p>
<p>After we released the editor on the desktop, we began the process of bringing it to mobile devices. This was a new frontier for this approach. On macOS, we just had to pass through keyboard and mouse events. On a mobile device, there are many subtle ways people can edit documents. There are auto-correct, speech-to-text, and clever ways to navigate documents. After some research, we found a neatly documented protocol -- <code>UITextInput</code> -- which outlines the various ways in which you can interact with a software keyboard on iOS. We also found a <a rel="external" href="https://developer.android.com/reference/android/view/inputmethod/InputMethodManager">corresponding document</a> in Android's documentation.</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5308aaf8-09b9-440e-802b-209b32204490_600x1300.gif"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5308aaf8-09b9-440e-802b-209b32204490_600x1300.gif" alt="" loading="lazy" decoding="async" /></a></p>
<p><em>(on iOS you can quickly move the cursor by long-pressing the spacebar)</em></p>
<p>So back to work we went. We expanded on our SwiftUI &lt;--&gt; egui integration giving it the ability to handle events that egui doesn't recognize. We piped through these new events, refined the way we handle mouse/touch inputs, and a couple of weeks ago, we merged our iOS editor bringing many of our gains to a new form factor.</p>
<p>We're very excited about the possibilities this technique opens up for us. It allows us to maintain the look &amp; feel that users crave while giving us an escape hatch down into our preferred programming environment when we need it. Once our editor is more mature and the kinks of our integration are worked out, we plan to apply this strategy to more document types. Long term we're interested in making it easy for people to quickly spin up their own SwiftUI component backed by Rust (as presently this still requires a lot of boilerplate code).</p>
<p>On net, the editor has been a big step forward for us. It's already live on desktops and will be shipping on iOS as part of our upcoming 0.7.5 release. It's a large and fresh body of work, so we anticipate some bugs. If you encounter any, please report them to our <a rel="external" href="https://github.com/lockbook/lockbook/issues">Github issues</a>. And, as always, if you'd like to join our community, we'd love to have you on our <a rel="external" href="https://discord.gg/lockbook">Discord server</a>.</p>
</content>
</entry>
<entry xml:lang="en">
<title>The story of how Lockbook created its own database for speed and productivity</title>
<published>2023-04-19T00:00:00+00:00</published>
<updated>2023-04-19T00:00:00+00:00</updated>
<author>
<name>Unknown</name>
</author>
<link rel="alternate" type="text/html" href="https://lockbook.net/blog/db-rs/"/>
<id>https://lockbook.net/blog/db-rs/</id>
<content type="html" xml:base="https://lockbook.net/blog/db-rs/"><p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fa91464-5596-4743-a17d-a324b4f43e8c_1018x994.png"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fa91464-5596-4743-a17d-a324b4f43e8c_1018x994.png" alt="" loading="lazy" decoding="async" /></a></p>
<p>As a backend engineer, the architecture I see used most commonly is a loadbalancer distributing requests to several horizontally scaled API servers. Those API servers are generally talking to one or more stores of state. <a rel="external" href="https://parth.cafe/p/introducing-lockbook">Lockbook</a> also started this way, we load balanced requests using HAProxy, had a handful of <a rel="external" href="https://parth.cafe/p/why-lockbook-chose-rust">Rust API nodes</a>, and stored our data in Postgres and S3.</p>
<p>A year into the project, we had developed enough of the product that we understood our needs more clearly, but we were still early enough into our journey where we could make breaking changes and run experiments. I had some reservations about this <em>default</em> architecture, and before the team stabilized our API, I wanted to see if we could do better.</p>
<p>My first complaint was about our interactions with SQL. It was annoying to shuffle data back and forth from the fields of our structs into columns of our tables. Over time our SQL queries grew more complicated, and it was hard to express and maintain ideas like <em>a user's file tree cannot have cycles</em> or <em>a file cannot have the same name as a non-deleted sibling</em>. We were constantly trying to determine whether we should express something in SQL, or read a user's data into our API server, perform and validate the operation in Rust, and then save the new state of their file tree. Concerns around transaction isolation, consistency, and performance were always hard to reason about. We were growing frustrated because we knew how we want this data to be stored and processed and were burning cycles fighting our declarative environment.</p>
<p>My second complaint was about how much infrastructure we had to manage. While on the topic of Postgres itself, running Postgres at a production scale is not trivial. There's a great deal of trivia you have to understand to make Postgres work properly with your API servers and your hardware. First we had to understand what features of Postgres our database libraries supported. In our case, that meant evaluating whether we needed to additionally run PGBouncer, Postgres' connection pooling server, and potentially another piece of infrastructure to manage. Regardless of PGBouncer, configuring Postgres itself requires an understanding of how Postgres interacts with your hardware. From Postgres' <a rel="external" href="https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server">configuration guide</a>:</p>
<blockquote>
<p>PostgreSQL ships with a basic configuration tuned for wide compatibility rather than performance. Odds are good the default parameters are very undersized for your system....</p>
</blockquote>
<p>That's just Postgres. Similar complexities existed for S3, HAProxy, and the networking and monitoring considerations of all the nodes mentioned thus far. This was quickly becoming overwhelming, and we hadn't broken ground on <em>user collaboration</em> , one of our most ambitious features. For a team sufficiently large this may be no big deal. Just hire some ops people to stand up the servers so the software engineers can engineer the software. For our resource-constrained team of 5, this wasn't going to work. Additionally, when we surveyed the useful work our servers were performing, we knew this level of complexity was unnecessary.</p>
<p>For example, when a user signs up for Lockbook or makes an edit to a file, the actual useful work that our server did to record that information should have taken no more than 2ms. But from our load balancer's reporting, those requests were taking 50-200 ms. We were using all these heavy-weight tools to be able to field lots of concurrent requests without paying any attention to how long those requests were taking. Would we need all this if the requests were fast?</p>
<p>We ran some experiments with Redis and stored files in EBS instead of S3, and the initial results were promising. We expressed all our logic in Rust and vastly increased the amount of code we were able to share with our clients (core). We dramatically reduced our latency, and our app felt noticeably faster. However, most of that request time was spent waiting for Redis to respond over the network (even if we hosted our application and database on the same server). And we were still spending time ferrying information in and out of Redis. I knew something was interesting to explore here.</p>
<p>So after a week of prototyping, I created <a rel="external" href="https://github.com/parth/db-rs">db-rs</a>. The idea was to make a stupid-simple database that could be embedded as a Rust library directly into our application. No network hops, no context switches, and huge performance gains. Have it be easy for someone to specify a schema in Rust, and allow them to pick what the performance characteristics of these simple key-value style tables would be. This is Core's schema, for instance:</p>
<pre><code>#[derive(Schema, Debug)]
pub struct CoreV3 {
pub account: Single&lt;Account&gt;,
pub last_synced: Single&lt;i64&gt;,
pub root: Single&lt;Uuid&gt;,
pub local_metadata: LookupTable&lt;Uuid, SignedFile&gt;,
pub base_metadata: LookupTable&lt;Uuid, SignedFile&gt;,
pub pub_key_lookup: LookupTable&lt;Owner, String&gt;,
pub doc_events: List&lt;DocEvent&gt;,
}
</code></pre>
<p>The types <code>Single</code>, <code>LookupTable</code>, and <code>List</code> are db-rs table types. They are backed by Rust <code>Option</code>, <code>HashMap</code>, or <code>Vec</code> respectively. They capture changes to their data structures, <code>Serialize</code> those changes and append them to the end of a log -- one of the fastest ways to persist an event.</p>
<p>The types <code>Account</code>, <code>SignedFile</code>, <code>Uuid</code>, etc are types Lookbook is using. They all implement the ubiquitous <code>Serialize</code> <code>Deserialize</code> traits, so we never again need to think about converting between our types and their on-disk format. Internally db-rs uses <code>bincode</code> format, an incredibly <a rel="external" href="https://github.com/djkoloski/rust_serialization_benchmark">performant</a> and compact representation of your data.</p>
<p>What's cool here is that when you query out of a table, you're handed pointers to <em>your data</em>. The database isn't fetching bytes, serializing them, or sending them over the wire for your program to then shuffle into its fields. A read from one of these tables is a direct memory access, and because of Rust's memory guarantees, you can be sure that reference will be valid for the duration of your access to it.</p>
<p>What's exciting from an ergonomics standpoint is that your schema is statically known by your editor. It's not defined and running on a server somewhere else. So if you type <code>db.</code> you get a list of your tables. If you select one, then that table-type's contract is shown to you, with <em>your</em> keys and values. Additionally for us, now our backend stack doesn't require any container orchestration whatsoever: you just need <code>cargo</code> to run our server. This has been massive boon for quickly setting up environments whether locally or in production.</p>
<p>The core ideas of the database are less than 800 lines of code and are fairly easy to reason about. This is a database that's working well for us not because of what it does, but because of all the things it <em>doesn't do</em>. And what we've gained from db-rs is a tremendous amount of performance and productivity.</p>
<p>Ultimately this is a different way to think about scaling a backend. When you string together 2-4 pieces of infrastructure over the network, you're incurring a big latency cost, and hopefully what you're gaining as a result is availability. But are you? If you're using something like Postgres, you're also in a situation where your database is your single point of failure. You've just surrounded that database with a lot of ceremonies, and I'm skeptical that the ceremony helps Postgres respond to queries faster or that it helps engineers deliver value more quickly.</p>
<p>db-rs has been running in production for half a year at this point. Most requests are replied to in less than 1 ms. We anticipate that on a modest EC2 node, we should be able to scale to hundreds of thousands of users and field hundreds of requests per second. Should we need to, we can scale vertically 1-2 orders of magnitude beyond this point. Ultimately our backend plans to follow a scaling strategy similar to email where users have a home server. And our long-term vision is one of a network of decentralized server operators. But that's a dream that's still quite far away.</p>
<p>As a result, what Lockbook ultimately converged on, is probably my new <em>default</em> approach for building simple backend systems. If this intrigues you, check out the <a rel="external" href="https://github.com/parth/db-rs">source code</a> of db-rs or take it for a <a rel="external" href="https://crates.io/crates/db-rs">spin</a>.</p>
<p>Currently db-rs exactly models the needs of Lockbook. There are key weaknesses around areas of concurrency and offloading seldom accessed data to disk. Whenever Lockbook or one of db-rs' users needs these things, they'll be added. Feel free to open an issue or pull request!</p>
</content>
</entry>
<entry xml:lang="en">
<title>Why Lockbook chose Rust</title>
<published>2023-01-02T00:00:00+00:00</published>
<updated>2023-01-02T00:00:00+00:00</updated>
<author>
<name>Unknown</name>
</author>
<link rel="alternate" type="text/html" href="https://lockbook.net/blog/why-lockbook-chose-rust/"/>
<id>https://lockbook.net/blog/why-lockbook-chose-rust/</id>
<content type="html" xml:base="https://lockbook.net/blog/why-lockbook-chose-rust/"><p><a rel="external" href="https://lockbook.net/">Lockbook</a> began it’s <a rel="external" href="https://parth.cafe/p/introducing-lockbook">journey</a> as a bash script. As it started to evolve into something more serious, one of our earliest challenges was identifying a UI framework we were willing to bet on. As we explored, we were weighing things like UI quality, developer experience, language selections, and so on.</p>
<p>Our choice of UI framework had implications for our server as well. If we chose JavaFX and native Android, we would likely want to choose a JVM-based language for our server to share as much code as possible.</p>
<p>As we wrote and re-wrote our application, we discovered that most of our effort, even on our clients, was not front-end code. When we were implementing user management, billing, file operations, collaboration, compression, and encryption, the lion’s share of the work was around traditional backend-oriented tasks. Things like data modeling, error propagation, managing complex logic, handling database interactions, and writing tests were where we were spending most of our time. Many of these things had to take place on our clients because all our user data is <a rel="external" href="https://en.wikipedia.org/wiki/End-to-end_encryption">end-to-end-encrypted</a>. Additionally, some of these operations were sensitive to slight differences in implementation. If your encryption and decryption are subtly different across two different clients, your file may be unreadable.</p>
<p>It was also becoming clear to us that the applications that looked and felt the best to us were created in that platform’s native UI framework. So our initial investigation around UI frameworks morphed into an inquiry into what the best repository for business logic was. Ideally, this repository would give us great tools for writing complex business logic and would be ultimately portable.</p>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8f9520-2b63-4f2c-ac05-20a12f699a82_612x408.jpeg"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8e8f9520-2b63-4f2c-ac05-20a12f699a82_612x408.jpeg" alt="Screenshot for " loading="lazy" decoding="async" /></a></p>
<h2 id="tools-for-managing-complexity">Tools for managing complexity</h2>
<p>Our collective experience made us gravitate towards a particular spirit. At <a rel="external" href="https://www.gemini.com/">Gemini</a>, <a rel="external" href="https://raayan.net/">Raayan</a> and I saw how productive we were within a foreign, large-scale, Scala codebase. Informed by the experience we were looking for a language with an expressive, robust type system.</p>
<p>A “robust type system” goes beyond what you’d find in languages like Java, Python, or Go. We were looking for type systems where <code>null</code> or <code>nil</code> were the exception, rather than the norm. We want it to be apparent when a function could return an error, or an empty value, and have ergonomic ways to handle those scenarios.</p>
<p>We wanted to have sophisticated interactions with things like <code>enums</code>, specifically, we wanted to be able to model the idea of exhaustivity. When an idea we were working with evolved to have more <em>cases</em> we wanted our compiler to guide us to all the locations that need to be updated.</p>
<p>There were a handful of other features we were looking for which can broadly be categorized into two similar ideas:</p>
<p>We wanted to express as much as we could in our primary programming language. Things that would traditionally be documented ( <em>this fn will return null in this situation</em> ) or things that would be expressed in configuration (TLS configuration handled by a different program in YAML) would ideally be expressed in a language that contributors understood intimately. Ideally in a language where the compiler was providing strong guarantees against mistakes and misuse.</p>
<p>We wanted our language and tools to help us detect defects as <a rel="external" href="https://en.wikipedia.org/wiki/Shift-left_testing">early as possible</a> in the development lifecycle. Most software developers are used to trying to capture defects at test time, but we found that trying to capture defects even earlier, at compile time, allowed us to drop into <a rel="external" href="https://en.wikipedia.org/wiki/Flow_(psychology)">flow</a> more easily. The following is our preference for when we’d like to catch defects:</p>
<ol>
<li>
<p>at compile time</p>
</li>
<li>
<p>test time</p>
</li>
<li>
<p>startup time</p>
</li>
<li>
<p>pr time</p>
</li>
<li>
<p>internal test time</p>
</li>
<li>
<p>by a customer</p>
</li>
</ol>
<p>Our strongest contenders for languages here were Rust, Haskell, and Scala.</p>
<h2 id="ultra-portability">Ultra-portability</h2>
<p>Ideally, this repository would not place constraints on where it could be used. If our repository was in Scala, for instance, we’d be able to use it on Desktop, our Server, and Android, but we’d run into problems on Apple devices.</p>
<p>We could use something like JS, virtually every platform has a way to invoke some sort of WebView which allows you to execute JS. But we’d had plenty of <a rel="external" href="https://www.destroyallsoftware.com/talks/wat">bad experiences</a> with vanilla javascript. We found that evolutions on JS like Typescript were also on a <a rel="external" href="https://www.youtube.com/watch?v=jjMbPt_H3RQ">shaky foundation</a>. Despite the JS ecosystem being popular and old, it didn’t feel very mature. Finally, we didn’t like the way most JS-based applications, whether <a rel="external" href="https://medium.com/commitlog/why-i-still-use-vim-67afd76b4db6">Electron</a> or React Native <a rel="external" href="https://parth.cafe/i/87442376/what-is-ideal">felt</a>.</p>
<p>Both JS and Scala would require tremendous overhead due to the default environments in which they run. We needed something lighter weight than invoking a little browser every time we wanted to call into our <em>core</em>. Our team members were pretty experienced in Golang, and <a rel="external" href="https://go.dev/blog/cgo">Cgo</a> was an ideal fit for what we were looking for. It would allow us to ship our <em>core</em> as a C library accessible from any programing language we were interested in inter-operating with. There were some concerns we had about the long-term overhead of <a rel="external" href="https://github.com/dyu/ffi-overhead">cgo</a> and garbage collection generally, but those wouldn’t be immediate concerns.</p>
<p>Similarly, Rust had a pretty rich collection of tools for generating C bindings for Rust programs and a pretty mature conceptualization of <a rel="external" href="https://en.wikipedia.org/wiki/Foreign_function_interface">FFI</a>. Though it wasn’t an immediate criterion we were inspired by the fact that most everything in Rust was a <a rel="external" href="https://stackoverflow.com/questions/69178380/what-does-zero-cost-abstraction-mean">zero-cost abstraction</a>. In that spirit, FFI in Rust would have virtually no additional overhead when compared to a C program. We were also drawn to <a rel="external" href="https://doc.rust-lang.org/cargo/">Cargo</a> which felt like the package manager for a language we were waiting for, particularly useful for our complicated build process.</p>
<p>Our strongest contenders for languages here were Rust, Go, and C.</p>
<h2 id="taking-the-plunge">Taking the plunge</h2>
<p>Learning Rust wasn’t a smooth process, but solid documentation helped us overcome the steep learning curve. Every language I’ve learned so far has shaped the way I view programming, it was refreshing to see the interaction of high-level concepts like Iterators, Dynamic Dispatch, and pattern matching discussed alongside their performance implications.</p>
<p>Rust has an interesting approach to memory management: it heavily restricts what you can do with references. In return, it will guarantee all your references are always valid and free of race conditions. It will do this at compile time, without the need for any costly runtime abstraction like Garbage Collection.</p>
<p>Once we were over the learning curve we prototyped the <a rel="external" href="https://github.com/lockbook/lockbook/tree/master/core">core library</a> we’d been planning, a CLI, and a Server that used it. During a period when many of us were rapidly prototyping many different solutions, this was the one that stood the test of time. Soon after the CLI, a C binding followed, then an <a rel="external" href="https://apps.apple.com/us/app/lockbook/id1526775001">iOS and macOS application</a>. Today we have a <a rel="external" href="https://en.wikipedia.org/wiki/Java_Native_Interface">JNI bindings</a> and an <a rel="external" href="https://play.google.com/store/apps/details?id=app.lockbook&amp;pli=1">Android app</a> as well. This core library will one day be packaged and documented as the <em>Lockbook SDK</em> allowing you to extend Lockbook from any language (more on this later).</p>
<h2 id="further-personal-reflections">Further personal reflections</h2>
<p>You can probably predict what your experience with Rust is going to be based on how you felt about the above two priorities. Rust is an experiment in the highest-level features implemented at no runtime cost. If you feel like the <code>Option&lt;T&gt;</code> is not a useful construct, you’re not likely to appreciate waiting for the compiler. If you don’t mind the latency introduced by garbage collection you’re not going to enjoy wrestling the <a rel="external" href="https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html">borrow checker</a>.</p>
<p>I wasn’t specifically seeking out performance, but before Rust, while programming there was always a slight uncertainty about whether I would have to re-write a given component in C, or spend time tuning a garbage collector. In Rust I don’t write everything optimally initially, when I need to, I’ll <code>clone()</code> things or stick them in an <code>Arc&lt;Mutex&lt;T&gt;&gt;</code> to revisit at a later time, but I appreciate that all these artifacts of the productivity vs. performance trade-offs are explicitly present for me to review, rather than implicitly constrained by my development environment.</p>
<p>For our team, learning Rust has certainly been a dynamic in onboarding new contributors. Certainly, we’ve lost contributors who didn’t buy into the ideas and were turned away because of Rust. But we’ve also encountered people who are specifically seeking out Rust projects because they share our excitement. It’s hard to tell what the net impact here is, but as is the case every year: Rust is a <a rel="external" href="https://survey.stackoverflow.co/2022/">a language a lot of people love</a>. Significant Open Source and Commercial entities from Linux to AWS are making permanent investments in Rust.</p>
<p>This excitement does however bring a lot of Junior talent to the ecosystem, subsequently, even though it’s roughly as old as Go, many of Rust’s packages feel like they’re not ready for production. By my estimation, this is because in addition to understanding the subject matter of the package they’re creating a maintainer of a library needs to understand Rust pretty deeply. Additionally, within the Rust ecosystem, some people are optimizing for different things. Some people are optimizing for compile times and binary size, while others are optimizing for static inference and performance, in many cases these are mutually exclusive values.</p>
<p>In some cases, this is a short-term problem as features are stabilized, and best practices are identified. In other cases, this is an irreconcilable aspect of the ecosystem that will simply result in lots of packages that are solving the same problem in slightly different ways.</p>
<p>This is something we should expect, as Rust is a language that’s trying to serve all programmers from UI developers to OS designers. And though it may cost me some productivity in the short term while I’m forced to contend with this nuance, in the long term it massively broadens my horizons as a software engineer.</p>
<p>Personally what got me over the steep learning curve is a rare feeling that the knowledge I’m building while learning Rust is a permanent investment in my future, not a trivial detail about a flaw of the tool I’m using. I’m very excited to see where Rust takes us all in the future.</p>
</content>
</entry>
<entry xml:lang="en">
<title>Introducing Lockbook</title>
<published>2022-11-29T00:00:00+00:00</published>
<updated>2022-11-29T00:00:00+00:00</updated>
<author>
<name>Unknown</name>
</author>
<link rel="alternate" type="text/html" href="https://lockbook.net/blog/introducing-lockbook/"/>
<id>https://lockbook.net/blog/introducing-lockbook/</id>
<content type="html" xml:base="https://lockbook.net/blog/introducing-lockbook/"><h1 id="a-new-note-taking-app">A new note-taking app</h1>
<p>Many moons ago my friends and I found ourselves frustrated with our computing experience. Our most important tools: our messengers, our note-taking apps, and our file storage all seemed to leave us with the same bitter taste in our mouths. Most of the mainstream solutions were trapped inside a browser, the epitome of sacrificing quality for the lowest common denominator. They didn’t pass muster for basic security and privacy concerns. Building on top of these systems was a painful experience. We were also growing concerned that we did not share the same ethics and values as the <a rel="external" href="https://bigtech.fail/">large companies</a> running these platforms.</p>
<p>So we ventured out into the land of FOSS. We built our systems from the ground up and experimented with self-hosted solutions. While we learned a lot from this experience, these solutions didn’t stand the test of time. As we brought our friends into this world, we found ourselves constantly apologizing for the sub-par experience. It felt like we solved some of our problems, but made other ones (UX) worse.</p>
<p>At this point, we took a step back. I knew we could do better. The apps we were being critical of weren’t some of the fresher ideas in computing. They are things that we’ve been doing for decades. Why don’t these products feel more mature? What should software that’s been around this long feel like?</p>
<h2 id="what-is-ideal">What is ideal?</h2>
<p>Software that’s been around this long shouldn’t be trapped in the browser. A browser is a convenient place for the discovery of new information, it’s not the place I want to visit for heavily used, critical, applications. When I look at my devices, whether on my iPhone or my Linux laptop, the apps I can use with the least friction are simple, native applications. They have the largest context about the device I’m using encoded into the application. This friction-free experience is why people reach for Apple Notes on their iPhones. And when they open those same notes on their iPad they find rich support for their Apple Pencil. For me, a minimal, friction-free context-aware experience is more valuable than feature richness.</p>
<p>Whatever experience I have on one device should carry over seamlessly to any device I may end up owning in the future. My notes shouldn’t be trapped on Apple Devices should I want to transition to Linux. Very few actions should require a network connection, and any network interactions should be deferrable so people outside of metropolitan areas don’t have a poor experience.</p>
<p>For now, likely most of these services will have to interact with some sort of backend. Everything that backend receives should be encrypted by the customer themselves, in a manner that nobody besides them and the people they give access to can see that content. We shouldn’t ask the customer for any information the service doesn’t require. There is very little reason that a user <em>must</em> provide an email address or a <em>phone number</em> to use a note-taking app. This level of security and privacy shouldn’t <em>cost</em> the user anything in terms of quality. Our customers may be whistle-blowers, journalists, or citizens living under oppressive regimes. They simply cannot afford to trust and they shouldn’t have to.</p>
<p>This software is too important to not open source. Any software claiming to be secure needs to be open source to prove that claim. Sensitive customers need the ability to build minimal clients with small dependency trees from sources on secure systems. Open-sourcing components like your server signal to the world that they can host critical infrastructure themselves, even if the people behind the product lose the will to keep the lights on. Open source doesn’t end in making the source code available, this software should be built out in the open with help from an enthusiastic community. People should be able to extend the tools for fun or profit with minimal friction.</p>
<h2 id="reaching-for-an-ideal">Reaching for an ideal</h2>
<p><a rel="external" href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb958cf3d-c608-4398-8d56-ca3429d86e26_1920x1216.jpeg"><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb958cf3d-c608-4398-8d56-ca3429d86e26_1920x1216.jpeg" alt="" loading="lazy" decoding="async" /></a></p>
<p>After much discussion, we decided that the best place to start was a note-taking app. We felt it was the product category with the largest room for growth. Architecturally it also paves the way for us to tackle storing files. And so began the three-year-long journey to create <a rel="external" href="https://lockbook.net/">Lockbook</a> a body of work I’m proud to say has stayed true to the vision outlined above. At the moment, Lockbook is not quite ready for adoption as it’s in the early stages of alpha testing. But I’d like to use this space to share updates on our progress as well as document how we overcame some interesting engineering challenges like:</p>
<ul>
<li>
<p>Productively maintaining several native apps with a small team</p>
</li>
<li>
<p>How we create rich non-web cross-platform UI elements.</p>
</li>
<li>
<p>How we leverage a powerful computer to find bugs.</p>
</li>
</ul>
<p>If you’d like to learn more about Lockbook you can:</p>
<ul>
<li>
<p><a rel="external" href="https://lockbook.net/">Checkout our website</a></p>
</li>
<li>
<p><a rel="external" href="https://github.com/lockbook/lockbook">Browse our source code</a></p>
</li>
<li>
<p><a rel="external" href="https://discord.gg/lockbook">Join our discord</a></p>
</li>
</ul>
<p>If you’d like to take an early look at Lockbook, <a rel="external" href="https://github.com/lockbook/lockbook/tree/master/docs/guides/install">we’re available on all platforms</a>.</p>
<ul>
<li>
<p><a rel="external" href="https://github.com/lockbook/lockbook/releases">Github Releases</a></p>
</li>
<li>
<p>Apple App Store</p>
</li>
<li>
<p>Google Play</p>
</li>
<li>
<p>Brew</p>
</li>
<li>
<p>AUR</p>
</li>
<li>
<p>Snap</p>
</li>
</ul>
<p>Parth’s Corner is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p>
<p>Subscribe</p>
</content>
</entry>
</feed>