Recent submissions

Comment · 5 years ago
Got it.

Not sure if this was clear here, but when you create an account on this site, the docs do sync to a server automatically. The encryption key is derived from users' passwords (Userbase handles that part). This way if users lose their locally persisted data, so long as they still have their password they're good to go (or vice versa). It's only if they lose both that they lose their data.

But still, given your experience, it does sound like it would be challenging to sell an exclusively offline product using browser storage. Appreciate the insight.

Comment · 5 years ago
There's also a challenge here where browsers will literally just start deleting data from IndexedDB if a user starts running out of space on their hard drive.

I added this statement: "Keep in mind this is a demo app subject to change in the future. You can download your docs at any time." as a warning to anyone who might be using this site with expectations that the data will be persistent.

Ultimately I figure the only solution for a production app is to either do a better job educating users on these issues, or scrap the offline persistence selling point entirely (and just rely on it as a cache).

What did you end up doing with your products?

Comment · 5 years ago
For starters, I think the number 1 most important thing is open sourcing code. Everyone should be able to read the entirety of the software's code themselves, verify the claim, build the app from source, and run it locally if desired. Unfortunately not everyone will have the skill to do this, so many will likely have to resort to trust in others to do this verification for them.

Given that this code also runs on a website, you have to trust that the code loaded from the website is the same as the source. Notice this statement I also added in there: "Please be aware: if someone evil... takes control of hushdocs.com, they can access your docs!"

There are some ways to mitigate this:

1. I could offer a native downloadable version of this site, and you can verify the downloaded file's integrity using a hash and signature.

2. I could add a service worker to the site such that after the website loads the first time, you have to manually allow a new version of the site (that would also be signed by me) to load and run in your browser. Check out this blog post for ideas on how to go about this: https://blog.airborn.io/post/2017/08/03/Transparent-Web-Apps...

3. I could host the static site on IPFS and you could rely on a browser extension to ensure the correct site loads, described here: https://blog.cloudflare.com/e2e-integrity/

But at the end of the day, to really verify the claim yourself, you have to be able to read and build the software from source yourself. Otherwise, yep, you are trusting that I'm giving you code that's doing what I say it's doing.

Comment · 5 years ago
Fixed. Sorry bout that. There was a circular reference in there when creating a new doc.
Comment · 5 years ago
Oof, my bad. Not just you. Fixing now!
Comment · 5 years ago
No worries, good question :)

For one, conflict merging sounds like it could be a nightmare with that approach. Like imagine you have 10 people working on a doc at the same time, and they each have different versions. Hush Docs takes care of keeping a doc in sync out of the box.

For two, real-time collaboration isn't possible with that approach.

For three, it's end-to-end encrypted if you care about that sorta thing.

Also just a note, comments and change tracking could be implemented pretty easily if there's interest. I spent like a week and a half on this, it's pretty barebones.

Comment · 5 years ago
Ah yes! Good point. Could work on a fallback for when IndexeDB isn't present :) It's probably still rough around the edges
Comment · 5 years ago
Hi HN,

Hush Docs is an offline-first, private Google Docs alternative. You can turn off your internet and the site works totally fine. Your docs are stored in your browser (using IndexedDB/Dexie.js), so you can create and edit your docs whenever you want, no internet or account needed. If you decide you want to sync across devices - or collaborate with others on a doc - you can create an account (which you do need internet for). Your docs are then end-to-end encrypted, so no server ever has access to your plaintext docs! Docs stay in sync using CRDTs (Automerge) - collaboration should be smooth even if someone works on a doc while offline for a while (like on an airplane with no wifi). Code is 100% open source. [1]

I decided to create this because someone asked for a tutorial on how to create offline-first apps using Userbase, which is a developer tool I’ve helped work on to make it easy to create secure and private apps [2][3][4]. I started out with a super basic tutorial, and then one thing led to the next and ya know: Hush Docs. A basic tutorial on how to build something like Hush Docs with Userbase is coming! [5]

Hush Docs is super barebones, so I’m calling it a "demo." If there's serious interest, I’d happily put more time into it and get it into something more production ready.

For reference, here are a couple other sweet E2E encrypted Google Docs alternatives I came across while scoping this out:

https://cryptpad.fr

https://www.airborn.io/

Airborn did something especially cool worth pointing out: they used a service worker to guarantee that code loaded into the browser came from the latest GitHub commit. [6]

[1] https://github.com/j-berman/hush-docs

[2] https://userbase.com

[3] https://news.ycombinator.com/item?id=22145168

[4] https://news.ycombinator.com/item?id=25869472

[5] https://userbase.com/docs/

[6] https://blog.airborn.io/post/2017/08/03/Transparent-Web-Apps...

Comment · 5 years ago
Should have been clearer, thank you!

And thank you for the algorithm!

Comment · 5 years ago
Comment · 5 years ago
Adding to this, properly defending against enumeration also sacrifices a level of security in addition to privacy, since the average user would likely need to store some additional identifiable data (such as an email) in our database in plaintext that would be compromised in a breach.
Comment · 5 years ago
Comment · 5 years ago
>Does it download the entire history of all transactions and replays them into the local database?

This is what clients do initially, until the database grows in size. Every time the transaction log increases 50 KB, the client takes a snapshot of the database's state at a particular point in time, compresses and encrypts it, and uploads this state to the server. We call this a "bundle". This way when clients reopen a database, they load from the bundle first, and then apply any new transactions that come after it. Rather than needing to query for the history of all transactions and decrypting them individually and reapplying.

>Hot do concurrent modification get resolved (several clients try to modify the shared stage at the same time)?

The server assigns each transaction a distinct sequence number via an atomic operation. So clients always apply transactions with the same distinct sequence number, in sequential order. The client relies on this to enforce uniqueness and versioning. Only the lowest sequence number itemId gets applied to a database if 2 clients insert with the same itemId at the same time, and similarly, only the lowest sequence number version of an item gets updated or deleted if 2 clients update or delete the same item at the same time.

With regards to bundling, it's a bit more complicated and there are layers to our approach in safely handling it under high concurrency. When a client uploads a bundle, the database records what sequence number the bundling took place at so clients can use it to retrieve the latest bundle. And the server retains copies of bundles at prior sequence numbers. This way if two clients attempt to open a database right around the moment a bundling process completes (client 1 receives a bundle at lower sequence number, and client 2 receives a bundle at a higher sequence number), both clients receive the same set of transactions regardless. The server sends all transactions in the log after the bundle sequence number, so client 1 just needs to decrypt and apply more individual transactions to rebuild the state compared to client 2.

Some may find this interesting too -- we specifically test for safe concurrent behavior across 2 clients using a makeshift testing framework that opens 2 browsers at the same time and does some neat tests: https://github.com/smallbets/userbase/tree/master/test

If you clone the repo and run `npm run test:concurrency`, it will run those tests and output test results to the consoles of the 2 browsers.

Comment · 5 years ago
Userbase is built on the assumption that in the event an attacker compromises the Userbase server and database, the attacker would not be able to access protected user data. We chose this assumption to build on because we figure that users and developers alike should assume that data stored at rest in cloud-based databases will eventually be leaked, as we've seen countless examples at almost every major company. Thus, we figured the default assumption is that usernames would not be expected to be private (and so yes, to answer your question, user enumeration is currently possible).

Additionally, practically defending against user enumeration beyond rate limiting sacrifices a level of security and privacy (for example, by requiring users provide an email to sign up to your service, or through some other means that likely ties the user to an identity and storing this in our database in plaintext), rather than allowing them to use pseudonymous usernames alone.

While we do recognize username enumeration is an issue (because users tend to reuse passwords from other sites, or don’t want to be found out using a site), we concluded that properly defending from user enumeration by default would have too material of a negative impact on user experience for little gain on top of what we already provide in way of protecting user data, and instead focused on defending against potential follow-up attacks by limiting brute force login attempts, and recommending that you tell your users to use a password manager at sign up.

The most significant place defending against enumeration affects is during sign up. When a user’s account already exists, we say the username is already taken, which isn't possible when properly defending against enumeration.

We're planning to allow you to enable email verification in your app if you want to, so users will need an email to successfully create an account. Once that's in place, we'll defend against enumeration more concretely. There are other places in addition to the salt retrieval that would be modified in similar fashion. For example, password reset will need to always successfully return even if a user provided the wrong username, and sharing a database with another user will always successfully return even if the other user doesn't exist (e.g. from a typo).

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton