Bitwarden compatible server written in Rust
github.com
github.com
The desktop app looks and feels like an electron app, so I'm far less impressed by it. At the very least it would be nice to have it in Qt or something like that.
I will freely admit I am strongly biased against Xamarin as there are so few cases where I think it's unequivocally the right choice, and Bitwarden isn't one of them. It would make more sense to take the work done in their desktop electron app and use that as part of an Ionic hybrid mobile app than to screw around with the layercake of bugs and mismatched APIs that Xamarin is. Moreover, since this is a serious app from a security point of view it really should go full vendor native IMO.
On iOS I pretty much stick with Castamatic and Overcast, both are full native iOS apps but neither are open source. I'm sure there's something listed at http://www.NewPodcastApps.com which is iOS and full Xcode native.
UPDATE: 21 Open source apps written in Swift (including one I use every day: Firefox for iOS): https://medium.mybridge.co/21-amazing-open-source-ios-apps-w...
[1] popular OpenStreetMap client, https://github.com/osmandapp/
[2] popular messaging app among privacy advocates, https://github.com/signalapp
Whatever you think of Xamarin, there is a special place in hell for all the buggy JS based mobile software. Its not an improvement, just a different flavour of crap.
> Moreover, since this is a serious app from a security point of view it really should go full vendor native IMO.
hmm
That is because it IS an Electron app.
> At the very least it would be nice to have it in Qt or something like that.
Sure, I hope so too. Unfortunately there are very few serious alternative password managers that are not using Electron for the desktop app these days. Seems like 1Password is on the way out too.
Do you want to share what makes you think Bitwarden is superior to other selfhosted, open-source solutions (e. g. Passbolt, Passwork, Psono)?
Feature wise (ignoring the mobile apps), some of those seem to have some comparable features like emergency access, sharing, folders, etc, but locked behind a pricing structure that makes them less useful.
So from a look at those other ones, Bitwarden is the superior product for non business/security conscious family use at least. And for business use I don't see how those other ones are better anyway.
> Bitwarden has an Android app (two of those didn't)
That's just wrong. All three of the alternatives I mentioned have an Android app. I haven't used any of them, though.
https://play.google.com/store/apps/details?id=com.psono.pson...
https://play.google.com/store/apps/details?id=com.passwork.p...
https://play.google.com/store/apps/details?id=com.passbolt.m...
> has been security audited (I didn't see anything for those other ones)
A quick search turns up at least some auditing activity:
Passbolt: https://www.passbolt.com/incidents
Psono: https://doc.psono.com/admin/asvs/overview.html (self-audit)
Looking more closely at Passwork, they claim to have open/auditable source code, but I can't find any public code. So they are out of the game anyway.
> Bitwarden has a much better pricing structure around non business users. It has a free tier and plans for families/non business users, as well as business use. Those others had nothing comparable that I could see except for a limited free tier.
Psono's full-featured enterprise version is free for anyone with up to 10 users. I don't see any such generous offer at Bitwarden or elsewhere.
And both, Psono and Passbolt offer unlimited business tiers for only 3€ per user per month which seems to be in the range of what Bitwarden costs. I don't really see your argument for the pricing.
For example, what happens if I get hit by a bus? Oh, they've already thought of that: https://bitwarden.com/help/article/emergency-access/
The peculiar problems faced by families, work organisations, 2fa - they've put some time into thing about every sub-problem I've come up with.
Well, just about everything. I'd love if they would let me run my own read only backup servers - ie, a server that mirrors my data stored on theirs, that my device will connect to if theirs isn't up, and that supports a read only version of the web interface.
Or is Rust finding a niche in userpace apps even though it was designed for systems level use? I am not saying apps shouldn't be written in Rust, I just don't understand the appeal. What am I missing?
Trendy enough that the very fact that rust tools happen to be written in that language is used as a main selling point.
A good type system is appealing regardless of the context.
The ecosystem can also be nice (or known) e.g. serde is amazing when dealing with all sorts of serialisation schemes. The tighter resource control can also be useful for application space, and it was most certainly one of the goals for vaultwarden as complexity aside the heft of the official server was a large part of the motivation (e.g. the ability to run it on a Pi or a small VPS)
An other longer-term option is that I can imagine e.g. coding something in rust then extracting its core or bits and bobs to libraries, and exposing that in C or Python or what have you. Nowhere near as attractive (or easy) with Go.
Go is appropriate for writing services / daemons, command line tools, servers, etc. It's not well suited for writing operating system code and very performance-intensive code (databases, audio/video, etc), but there's still a big overlap with Rust.
It seems to me that this whole discussion keeps coming up because parts of the Rust community are worried about the competition. And they have reason to be :-)
but there are DBs written in go.
First, thanks to default immutability of variables and the borrow checker, I trust that I'm far less likely to accidentally mutate something and cause an action-at-a-distance bug.
Second, I absolutely love idiomatic Rust error handling of returning a Result (especially combined with the question-mark operator). It forces me to deal with error conditions. Unlike C# or Python or Java or C++, I don't have to worry that any code could throw an exception at any time. (Rust code can panic, but panics generally represent unrecoverable errors — see http://joeduffyblog.com/2016/02/07/the-error-model/#bugs-are... ) And unlike Go or C, I don't have to remember to check the error every single time.
I still have to write functionality tests for Rust code, but once I've done that I feel like the code is mostly locked down. It's harder to get to that sense of security in other languages.
How long did that take and what resources did you use to learn?
Then I started working on a personal project, which motivated me to bull through lots of difficult problems. (This personal project happens to have been bindings for Apple Core Audio, but the point is to pick something you care about enough to motivate yourself.)
Finally, I've found users.rust-lang.org invaluable.
The first major challenge for me was the error handling ("WTF is `Box<dyn std::error::Error>`? What is `Box`? What is `dyn`?"). It got in the way as soon as I even tried to write command line utilities. Once you learn it, it's amazing, but out of the gate I continually stumbled and fell flat on my face.
The second challenge was harder: coming from OOP languages, I was accustomed to structuring everything as large mutable heap-allocated classes with private fields, accessors, and an emphasis on opaque data structures and encapsulation. That is not idiomatic Rust, so I had to unlearn it and discover architectural alternatives.
I don't know exactly how long it took before I felt comfortable, since I was learning in disconnected spurts rather than immersively all at once. It wasn't quick, though.
I just don't understand this logic. Exceptions are the same (C++ exceptions use the very same unwinding mechanism than panics in Rust as far as I can see), why would you forbid yourself to catch_unwind ? It's just making your software worse for no reason, users always will be happier with an app that shows a small "warning: internal error. Document backup saved in </some/place/>. $software will now shutdown", than seeing macOS or Windows's crash dialog.
The distinction is that panicking should (almost) never be used for recoverable errors. You can, but that's not idiomatic and would only be appropriate within the confines of your own application. Recoverable errors in Rust should be handled by return values, typically via either Result or Option.
This is unlike all the other options I listed (except Go, and C++ with exceptions disabled), where it is idiomatic to use exceptions to handle recoverable errors.
In theory, (strictly) checked exceptions are equivalent (isomorphic) to error codes as an error handling mechanism. But as soon as unchecked exceptions are allowed, it all falls apart and you must contend with the problem of "invisible control flow". Not having to deal with "invisible control flow" in Rust is one of the things that makes me much more confident that the code actually does what it looks like it does.
The Joe Duffy blog post I linked to earlier compares various error handling methods, including checked exceptions. It's very long, but interacting deeply with this blog post helped me to level up my understanding of error handling. FWIW I did a presentation on Duffy's article for the San Diego chapter of Papers We Love: https://www.youtube.com/watch?v=GwPBC4mWfFQ
I know that this is a fairly contrarian take, but I strongly believe than the emphasis on idiomatism is more harm than good. The only thing that matters is the language spec - everything that fits in there is kosher. Idioms just create pointless fights and tabs vs spaces situations where there doesn't need to be any.
> Not having to deal with "invisible control flow" in Rust is one of the things that makes me much more confident that the code actually does what it looks like it does.
no, you just choose to ignore it. I can also write C++ code with throw and no try..catch and that will give the same result (as I pretty much use exceptions like one would use panic! in rust). I don't know anyone who would say that this is a good idea. My sweet spot is to have a few catch handlers around the main loop which catch 99% of the unrecoverable issues, and sometimes, when it turns out that an issue has a way to be recovered (or that maybe it doesn't matter), then someone gets a try..catch block.
Like most articles about exceptions, that Joe Duffy post talks about the problem of "where the control flow goes". I've written my first lines of C++ something like 17-18 years ago now and not once it has actually been an issue. Consultants sure do love selling it as one though.
My response is that adherence to common idioms is simultaneously beneficial and harmful. It is beneficial because shared assumptions and shared understanding facilitate cooperation, yet it is harmful because it impedes innovation. Whether it is more beneficial or more harmful on balance depends on the situation and on individual taste.
I'd like to think that our perspectives are compatible.
> > Not having to deal with "invisible control flow" in Rust is one of the things that makes me much more confident that the code actually does what it looks like it does.
> no, you just choose to ignore it.
I guess you could characterize things that way. For example, in the Rust library code I write, I choose to ignore certain unrecoverable errors — e.g. out-of-memory panics from allocating ordinary sized objects, even though such panics can theoretically occur.
But the distinction here is that I also expect e.g. invalid argument values or "file not found" errors to be handled via Rust's Result type. I don't choose to ignore such events — I expect all recoverable errors to be handled via visible control flow, where you can identify every location in the code that such an error might occur. This makes it easier to reason about control flow for all circumstances save unrecoverable errors.
> My sweet spot is to have a few catch handlers around the main loop which catch 99% of the unrecoverable issues
Yes, that's an Anders-Hejlsberg-endorsed way of doing things. "The exception handling should be centralized, and you should just protect yourself as the exceptions propagate out to the handler." https://www.artima.com/articles/the-trouble-with-checked-exc...
I think the preference for one way of doing things can depend on what problem domain you work in. That approach is highly suitable for applications programming.
(Duffy has done a lot of work on operating systems; my biggest projects have been libraries.)
> Consultants sure do love selling it as one though.
EDIT: I'm not very happy about that take, and I originally wrote up a lengthy response — but it turns out I had incorrectly recalled that this was not the first such interaction we've had. (I was recalling an obnoxious post from a different European with the first initial "j"). I've deleted my response because it's OT and not worth dealing with if it's not something recurring.
How do you mean? I’ve been writing Rust frequently lately and you still have to check the case. Do you mean that the compiler will nag you if you stunt so you don’t have to remember to do it because you’ll be reminded?
That’s one of the things common Go linters do that I wish was built into the compiler. It’s silly that an unused dependency is a compiler error but an unchecked error/return value is not.
It's easy and idiomatic to write code which calls `unwrap`, so that's what everybody does when they don't want or need to write sophisticated error handling code. But that's not the same as forgetting to check a return value — when something goes wrong, `unwrap` panics.
I mean, if you're determined you can definitely drop an error in Rust, e.g. with a `match` arm that does nothing. But the easy path is to `unwrap`.
unwrap feels lazy, but it's obvious what is doing and it's impossible to do nothing. With go error handling is entirely optional.
A quick back of the paper example, I am doing Advent of Code this year and the same exact implementation took 40 ms in Rust and 350 ms in Go. Not to mention the Rust implementation, despite being the same semantically, was more concise and clear due to Rust’s extensive Iterator trait methods. A small difference you might say, but it’s just one less reason for me to switch.
If you've been looking at go, it's really not much of an investment to try it out (I wouldn't heartily recommend it as I dislike the language but you do you).
rust is fantastic for building highly performant safe code at the expense of developer productivity. builds times are atrocious and tooling isn't as polished as golang.
both at great languages.
Go was designed to be a language that development scales very well with it's focus on simplicity and very fast compile speed.
Rust on the other hand, was designed to make certain hard things less hard, at the cost of complexity, ease of learning, speed of development (high amount of restrictions) and compile speed. If you have a multi-million line monolith made in rust, I bet your compile speed and edit-build-run cycle will take a very long time and be very painful compared to the same golang one. Hiring will also be harder because the minimum IQ & experience bar is higher and you couldn't have productive jr engineers get up to speed on it nearly as quickly.
I agree the single file argument is not extremely convincing. Especially because engineers are often on Mac on Windows machine and compiling for Linux. While Go does support this, as soon as you have to use a c library dependency (in my experience this was sqlite), then we had to start compiling in the environment we wanted. Easy to solve with docker but deployment wasn't the reason I like Go.
I should spend some time thinking about why but overall I just "feel" more productive with Go vs Java (including Kotlin). Go's standard library, docs (with links to the source code), everything just feels super readable and understandable.
I don't see much debate agains Go using less memory. I can confirm this was my experience as well. My experience is that it uses a lot less CPU as well.
No it isn't. On many times I've been able to simplify golang code that is dozens of line long into something that is only a few lines long in Java, while improving readability and reliability. This is especially useful when exploring a new code base and spending a lot of time perusing boilerplate trying to figure out what's going on.
I’ve been working through the latest AoC in Rust and it’s been eventually very nice looking once I’ve got all the functional features used correctly, but my Go solutions from last year are also elegantly read.
The biggest difference to me is explicitly managing memory or not. This is neither an explicit advantage or disadvantage though. In some cases, it’s tremendously powerful, and in others, it’s an unnecessary cognitive load.
Firefox has portions written in Rust. 1passwd, Dropbox etc...
If you use Visual Studio Code, it uses ripgrep which is built in rust.
I use Rust for most of my servers now. It's replaced Python + flask in many cases, without too big a difference in my code.
People are confused about what system programming means and a lot of that confusion comes from parts of the Rust community which want to carve out a niche for Rust and keep claiming that Rust is particularly suited to system programming, as opposed to Go or D or other languages which are in reality also capable of tackling many system programming jobs, but have a garbage collector.
Which is to say, accessing a client may or may not be thread safe (depending on the client implementation) but assuming it’s not a multiplexing client, it almost certainly uses some kind of locking mechanism under the hood
Even if it is a multiplexing client, if you saturate the internal clients you will either need to wait for a client to stop writing to its socket (through perhaps a lockless consumer model) or create a new internal client (slow).
Concurrency problems don't magically disappear because your language can check for them. You still need to use memory-safe patterns, but the compiler will force your hand and prevent you from doing unsafe things accidentally.
In the end, this makes it far easier to build correct, concurrent applications. If you decide to try some fancy new pattern that doesn't require locking, the compiler can guarantee the memory safety of your new implementation.
For a reasonable amount of locking, The Arc / RwLock dance offers good performance (other languages, like Swift, use something like Arc for every property access (although the compiler tries to optimise it away)).
The safety is actually better because you're forced to think about the failure case. I don't have good memories of Objective-C where some Foundation calls don't throw (in they don't have an error parameter), but just throw random undocumented exceptions. (Not saying that some Rust calls don't panic, but knowing that something can go wrong is much better than learning about it in production).
I had heard of Bitwarden before, and looked into it. The stack struck me as incredible for a security product: numerous services that need to be updated in-sync provides a wide surface area for attack, and ultimately encourages you to use their managed solution, IMO. Keepass is better, but the surface area is still quite broad.
Ultimately, I settled on `pass`[1], made by the creator of wireguard. It takes advantage of a clever inversion of responsibilities, where clients store the passwords and sync with git. You can have a "dumb" git remote with no local private key; even if compromised there's not much to consume. Encryption is powered by GPG, so the security surface area is managing your private keys, which is a very well-understood problem.
It's probably the best product for security-minded hacker types. As a simple offering (a shell wrapper around GPG + git), it's easy to build clients for, which means there are many OS/browser-integrated clients to choose from. Similarly, it was trivial to import everything from Lastpass.
Maybe most important of all, once setup, it passed the spouse/parent test for me. They needed me there for setup, but once setup I haven't needed to give additional support for the last year, ymmv.
I take care of the sync (syncthing) but anything would work.
I've never had issues with keepass's auto type so i wonder why it isn't as popular
Mobile used to be aam issue earlier but there's now a top notch implementation keepassdx that's on f droid
I had been planning on switching over to Bitwarden in a couple months when my current LastPass subscription runs out, but I just found out that LogMeIn is spinning them off into a separate company again - https://www.zdnet.com/article/logmein-announces-plan-to-spin...
That's why I have them disabled in my gmail accounts, I have several missed important emails because they landed in the wrong section. I disabled them in my work email too. My boss keep it on and it causes my boss issues with missing RFQ and requests.
I went with Keepass, it is free, open source, cross-platform. Been using Keepass for 10 years. I control my data and my file, so I don't need to worry about potential data breach which several other SaaS password management failed to keep it secure. My keepass database (vault) resides in my OneDrive and synced across all of my devices that have Keepass. And I like Keepass will generate a backup of the database before saving the entry in case of corruption. It happened to me once 5 years ago and it was in Dropbox storage that time, somehow Dropbox failed to sync the change and ended up corrupting the synced vault across of my devices. I have 260+ entries in my keepass.
Neat thing about Keepass, it can check haveibeenpwned.com and compare the password in my vault. It generated a list of password that need to be changed.
You can arbitrage by trying to choose more than one. But IMO, the most robust solution is to make your data "dumb" and commoditize the storage layer.
With something like pass, I have my passwords physically located on all my devices, encrypted at-rest. Plus, I have a backup on a home server that can be regularly backed up to any commodity storage provider (backblaze, aws, whatever).
With this, you'd need to both lose (1) all your devices (2) internet access to those devices. This kind of thing is a bit predictable, and can be mitigated.
With a managed secret-manager service, mere corporate shenanigans or internet connectivity problems can take them away from you! Those are less predictable, and the only mitigation is to move to a service that doesn't have these problems.
So yeah, resource usage is real, especially if you plan to run this on a Pi or on small cloud intances.
Call me old fashioned, but that seems like an insanely large amount of resources to host one person's passwords.
Licensing, sure. It's more convenient with Free software for small self-hosted instances... But the rest? You can even get a Linux build in a docker container supplied by MS...
[1] https://bitwarden.com/help/article/install-on-premise-linux/
Mostly it's that the official setup is the same thing that runs their free/paid hosted service. By design, it is quite split apart into separate areas, presumably so they can scale independently of each other: https://github.com/bitwarden/server/blob/master/SETUP.md
But most people are going to want to host self-hosted instances for themselves, their families, or maybe a small company. The official server might be the best route if you're deploying to thousand of users, but that won't be most people.
Another benefit is that this flips all of the "paid" feature flags to true. If you self-host Bitwarden's official setup you still have to pay a subscription to use paid features.
As a developer and cheapskate user myself, I understand the appeal of this.
As a product builder, I struggle with what this means to build a business upon an open core model.
I do feel a little bad using the client applications for free given their business model revolves charging for the backend only.
I still have to dig into the Organization feature to share passwords with my partner.
I uses KeepassXC with OneDrive without syncing issue. I set OneDrive on all on my devices to keep the KDBX file locally and sync it from the cloud if there is any change. Only syncing issue I have is with Dropbox, moved to OneDrive and never have issues with keeping it synced so far. If OneDrive went down, the KDBX file will be there because it is set to keep the file locally.
But there is also an old saying in IT: no backup no mercy
Note that the official clients phone home; you have to block them from doing so.
But in this particular case, i think GO would have been a much better alternative, we'll see how it goes in the long term
no GC no JIT, server starts instantly, you need to allocate less resources, and it's easier to install, no runtime dependencies, usually, if done correctly
but i am not closed minded, i understand pros/cons of each features
in that particular case, a GC is helpful even though i'm personally against it
i'm being objective rather than subjective whenever i have to make a choice or a suggestion