cubby put ideas
cubby publish put ideas
cubby get ideas
- Command line-based, free, open source, cloud note-taking and storage tool
- A Neovim plugin to access your Cubby blobs from the best editor ever
- End-to-end AES-encrypted by default
- Full version history, with the ability to revert to any prior version
- Share personal notes, config files, and data between your computers
- Publish potentially sensitive data using end-to-end encrypted web sharing
- Collaborate with other Cubby users securely and efficiently
- Maintain privacy in the presence of spyware
- 100MB of storage totally free forever
Your average (technically proficient) user of the command-line -- for all the tools and skills they have access to -- no doubt has numerous text files scattered around their filesystem containing important bits of information. Things like:
- To-do lists
- Passwords and other user credentials
- Notes
- Cryptographic keys
- Settings, like terminal settings in
.bashrc
or SSH key settings in.ssh
Many of these are scattered around in random text files and documents.
Worse yet, others -- like your favorite configs and keys -- need to be arduously copied among computers in a vain attempt to tame chaos and keep your config files in sync.
Notes and to-do lists become siloed between "work computer" and "personal computer," and one must take care to always be at the right computer when having thoughts or questions about a particular domain.
Alas, Cubby is here to fix all these problems. It was designed specifically for the highly technical, CLI-loving programmer type. In Cubby, viewing your to-do list takes some 4 keystrokes with the standard set of aliases, whereas viewing a to-do list on Notion would involve clicking around clumsily like a mere technical peasant.
Add up all that time and you're losing years of your life to clunky tools designed for people who don't know how to
use vim
and refuse to learn.
All that to say -- try Cubby now. There's a super quick and easy install script that sets up your configs, downloads the binary, and makes an account if necessary. Five minutes to learn Cubby now may save you years of productivity yet.
Cubby is a secure blob storage tool optimized for command-line users that can function as a personal organizer, note-taking tool, time tracker, secret sharing platform, configuration mechanism, or blog publishing system, among many other things.
At the most basic level, Cubby allows users to read and write blobs like so:
cubby put "janes phone number" 2125551212
cubby get "janes phone number" # opens in $EDITOR by default (vim, emacs, etc.)
These blobs are securely stored on the server without exposing any sensitive data to the server at all -- all data is AES-128 encrypted (and decrypted) on the client side. Only ciphertext is stored on the server.
Taking a few minutes to set up and learn Cubby can save the average user a huge amount of time, effort, and mental overhead by providing an easy, straightforward way to store important bits of information. Take a look at the use case examples below for ideas on where to start.
Some example use cases for Cubby:
- Unifying shell configs across all your computers
- Privacy while using work computers
- Writing a developer blog with Cubby
- A general note on the motivation for Cubby
For most flavors of UNIX/Linux and Mac OS X, simply run:
curl -s -S -L https://www.cubbycli.com/static/install.sh | bash
This will set up a config file in $HOME/.cubby
and download the Cubby binary to $HOME/.cubby/bin
.
The repository defines two binaries in cmd
: a client and a server. By default, the client will use the publicly
available server at public.cubbycli.com
, but users can choose to run a private server instead.
Create a cubby-client.yaml
file in your $HOME
directory with contents as follows:
host: https://public.cubbycli.com
port: 3737
options:
viewer: editor
body-only: true
user:
email: [email protected]
password: passwordhere
crypto:
symmetric-key: sometexthere
mode: symmetric
Next, run:
cubby signup
You should see a success message and you're ready to go.
Before doing the walkthrough, be sure to install Cubby via the instructions in the "Installation" section above. (For most users, this simply involves running the install script.)
The first time you start up Cubby, you won't have any blobs. Let's start by making a first blob -- a to-do list. Start by running:
cubby put todo
This creates a new, empty blob at the root of our blobspace called todo
.
Next, we're going to edit this blob. Before we do that, make sure you have set an $EDITOR
environment variable
to edit the blob body. If none is provided, we default to vim
. If you wanted to use nano
, for example, you could do:
export EDITOR=nano
Now we can edit our blob. Simply run:
cubby get todo
This will open up your todo
blob in vim. Edit it to contain whatever you want, and then save and exit when
you're done. Because our configuration file specifies encryption mode symmetric
, our updates will be
encrypted automatically before being sent to the server (using a key derived from the password you set
in place of passwordhere
).
Let's make a new blob that will ultimately contain a public-facing blob post. To do this, let's first
initialize a blob called posts
at the root of our blobspace:
cubby put posts
We're actually not going to use posts
to store content -- it's being used kind of like a "directory" to
organize our posts in one spot.
Let's make a child blob of posts
(like a "file" in the "directory") that will actually store a
blog post we'll share with the world. This first one, like most blog posts, will not be encrypted;
we want anyone who wants to read it to be able to read it. (Of course, all data is delivered
over a secure connection, regardless of user encryption settings.)
To accomplish this, we'll add some new things to our cubby put
:
- We'll introduce the encryption mode (
-C
) flag. This flag allows you to specify what type of user-level of encryption to use for this blob. Yours is defaulted tosymmetric
encryption incubby-client.yaml
file, so for a blob we want to share publicly, we need to override that setting and make it unencrypted with-C none
. - We'll make this blob as a child blob under the parent
posts
using paths (as discussed under "Concepts").
All together, it looks like this:
cubby put -C none posts:helloworld
In order to see how this created a child blob under the parent posts
, run:
cubby list
This will list out your blobs, suitably indented to illustrate parent-child relationships. You'll see your
helloworld
blob is under posts
, for example.
Now let's open up our post and edit it to contain some content for our blog post:
cubby get posts:helloworld
You've probably noticed that paths are represented in Cubby with a colon (:
). Anywhere that you're
expected to pass a blob ID of some kind, you can pass a colon-separated path like this instead, and
it will be automatically resolved to the proper blob ID.
Let's use cubby get
again to fill out the post with some Markdown like the following so we have
interesting content to look at for the rest of the tutorial:
# Hello, world!
Hello, world! Welcome to Cubby. We hope it saves you a ton of time and aggravation.
Next, we're going to "publish" this blob for the world to see. That's super easy with Cubby! Just run:
cubby publish put posts:helloworld
You'll see something like:
No permissions provided - defaulting to public...
Published successfully, getting URL...
Web: https://public.cubbycli.com:443/v1/post/jason8081/helloworld/view
API: https://public.cubbycli.com:443/v1/post/jason8081/helloworld
If you go the URL listed under Web
, you'll see your post fully rendered as HTML. To make changes to your post,
simply edit your blob with:
cubby get posts:helloworld
Any changes you make will be automatically reflected at the post URL.
But what if you want to share something secret, and you only want a specific audience to be able to decrypt your message? Easy enough. In this last example, we'll still make our post publicly accessible, but we'll encrypt it so the user has to enter an encryption passphrase when they go to read it.
However, we want this to be a passphrase we're comfortable sharing -- in other words, we don't want to reuse our standard Cubby encryption passphrase, which secures our personal data.
To accomplish this, we'll introduce the encryption key (-K
) flag. This flag allows you to use a different encryption key
from the one configured in your cubby-client.yaml
file. Here, we're setting the passphrase to share_password
.
cubby put -K share_password posts:secret_post
cubby get -K share_password posts:secret_post # edit the post contents
cubby publish put posts:secret_post
When you go to the web link returned by cubby publish
, you'll see a page prompting you to enter the encryption passphrase.
Once you enter share_password
and click "Decrypt", the content of your post will appear as fully
rendered HTML.
Now, when you go to the URL for that post, no encryption password will be required in order to view the content.
The central concept in Cubby is the blob. A Cubby "blobspace" is simply a collection of blobs, where each blob can itself have "child" blobs, like files in a directory. A blob has a number of attributes:
- A title, similar to a filename, which is used to uniquely identify the blob
- Some body text, which may be encrypted or plaintext
- A type, which specifies the type of content and informs how it is rendered on the web app
- Tags, which can be any string, and which allow you to quickly
cubby search
for particular types of blobs - Attached files, which can be unencrypted or encrypted
- Expire time, which optionally specifies a "time-to-live", i.e. a time at which the blob is automatically deleted
- A complete version history
- Some number of "child" blobs
Paths allow you to address blobs in your blobspace. They are simply colon-separated lists of blob titles, from root to leaf.
For example, say we have a blobspace set up so the output of cubby list
is as follows:
posts
helloworld
plaintext_post
To address the posts
"parent" blob, we would simply use posts
(e.g. cubby get posts
).
To address one of its children, however, such as helloworld
, we would use
posts:helloworld
(e.g. cubby get posts:helloworld
).
If we add a child below helloworld
called hw_child
, we could address it with the
path posts:helloworld:hw_child
, i.e. cubby get posts:helloworld:hw_child
.
The colon-separated notation gives us an easy way to name our blobs and locate them within their hierarchical blobspace. But we're still doing a lot of unnecessary typing! That's where prefix paths come in. Instead of providing the full blob titles as the segments in a path, you can instead use prefixes wherever the use of such prefix would not create ambiguity. (If it does create ambiguity, an arbitrary response wil be returned.)
Say, for example, you have a blobspace that has these blobs:
places
alabama
austria
burbank
If I'm looking up burbank
, I could run:
cubby get p:b
Since there is only one root blob starting with p
and one child of that root
starting with b
, the path p:b
is unambiguous. If, however, I wanted to look
up austria
, I'd need to instead do:
cubby get p:au
Because there are two blobs under places
starting with a
, I need to provide an
extra letter to make the path unambiguous.
Any blob -- encrypted with any key or in plaintext -- can be "published" via Cubby. The details of how the shared version of the blob work depend on the configuration of the blob itself. The main two details to consider are the type of the blob and its encryption settings.
Currently, the only "special" type for shared blobs is Markdown, which is also the default type for a new blob,
as demonstrated in the walkthrough above. Blobs with type set to markdown
will be treated like
"blog posts" -- they will be visible both via API and on the web at a generated URL. On the web, the Markdown
will be properly converted into HTML and syntax highlighting will be applied to code snippets.
If a blob is encrypted, the users attempting to access it -- whether by web, CLI, or API -- will need to have the proper symmetric key passphrase in order to decrypt its contents. Typically, users don't want to give out their personal encryption key, so there are two things we can do instead:
- Pass
-C none
on thecubby put
, which disables encryption completely. When this blob is published, it will be a fully public post that anyone with the URL can view. - Pass
-K <key>
with a special key only for this share. When this blob is published, users will only be able to view it with that key. You can communicate this offline to the intended audience, and this way the shared data is never exposed to the server or to the public.
Virtually all configs -- every one except the title/data fields for cubby put
-- are controlled by both Cobra
and Viper. This means you can set your defaults in cubby-client.yaml
and override them as needed with
command line flags. Running cubby help
will show you a full list of both the config file key and
command line switch versions for each variable. (Note that, for config file keys, the period .
denotes
keys that are nested in the YAML file, e.g. crypto.mode
, where mode
is under the block crypto
.)
View and download file attachments to blobs.
Users can pass attachments with the -a
flag to cubby put
, e.g.:
cubby put -a README.md files:readme
The attachments
subcommand allows you to view the attachments with cubby attachments <blob path>
,
which produces a list of files attached the blob. To download one or more files, which may or may
not be encrypted, use the -F
switch, e.g.:
cubby attachments <blob path> -F <filename>
Usage: cubby attachments <blob path> [-F <filename>]
Usage: cubby attachments backup:file -F file.dat
Output the body of a blob to STDOUT.
Effectively, cubby cat
is equivalent to cubby get -b=true -V=stdout
.
Usage: cubby cat <key>
Example: cubby cat todo
View and update a blob.
get
opens the blob's body contents in the viewer configured in options.viewer
. By default, this is set to editor
,
which opens the blob in your system's default editor (as defined by $EDITOR
). It can also be set to stdout
or viewer
for read-only use cases.
Nested blobs can be retrieved by using colon-delimited paths of form root-blob:child-blob
--
e.g. notes:client meeting
.
Usage: cubby get <key>
Example: cubby get todo
Optional parameters include:
-V
: override configured viewer (one ofeditor
,stdout
, orviewer
) --stdout
is often used when calling Cubby from a script-b
: when using stdout, shows body only (default: true)
Pull down each blob in your blobspace, decrypt it, and search it for a substring. Regular expression support is forthcoming.
Usage: cubby grep [-i] <substring>
Example: cubby grep bonjour
Optional parameters include:
-i
: case insensitive search
The most important command of all: help
. You can use help
(or -h
) on both the root cubby
command
or on any individual subcommands. For example, to get a list of all subcommands and global options,
run cubby help
, but to get options for cubby put
specifically, run cubby put -h
(for some commands, help
can be mistakenly interpreted as a blob path).
Usage: cubby help
Example: cubby help
List blobs.
list
shows all active blobs, intended to illustrate parent-child relationships.
Usage: cubby list
Appends a single line of text to a blob.
Usage: cubby push <path> <new line>
Usage: cubby push notes "TODO: buy thanksgiving turkey"
Puts a new blob into Cubby.
Usage: cubby put <key> <value>
Example: cubby put myemail "[email protected]"
Optional parameters include:
-a
: attach file to blob, e.g.-a file.txt
-2
: add blob as a child to another blob (specified by colon-delimited path), e.g.-2 path:to:parent
-g
: add a tag, e.g.-g work
-X
: add a TTL, e.g.-X 365d
Revert a blob to a prior version.
Blob should be specified by its ID or path. The user will be prompted to view the version history and provide a revision number to which Cubby will revert the blob's contents.
Usage: cubby revert <blob path>
Usage: cubby revert blog:hello-world
Search blobs.
Searches titles, tags, and unencrypted body text.
Usage: cubby search <substring>
Example: cubby search email
Signs up a user identity.
By default, this subcommand takes the username and password from your cubby-client.yaml
file. Be sure to set up this
config file before running signup.
Usage: cubby signup
Upgrades the Cubby binary to the latest version.
Usage: cubby upgrade
Shows current version information for the Cubby client.
Usage: cubby version
Cubby was written, first and foremost, to solve my personal needs. The default Cubby server now
publicly available at public.cubbycli.com
was previously for personal use only. But as I've
used Cubby more and more, I've come to think that it's worth sharing with the world in hopes that you
all find it useful as well.
I wanted a way to interact with my personal data that was fast, efficient, and centered around
a command-line interface. To be clear, I don't mean a CLI utility, a companion to some larger app
or service, but rather an experience designed from the ground up for the command-line. With Cubby, all
my personal data is just a few keystrokes away; my default editor is the highly-powered vim
, which
lets me edit my stuff -- again -- efficiently. With the help of macros and buffers and yanks.
Likewise, important files, such as cryptographic keys and identity files, are immediately available
at every computer I have. Simply running cubby get <whatever>
pulls down these critical pieces
of data that I need to copy to every computer, cloud server, and container I run.
Aside from being an extremely fast an efficient way to work with personal data, Cubby is useful for managing personal notes in which you may sometimes mention matters from work. For example, you remember something to do for a client at work, and you want to write "get back to client X" on your to-do list. Exposing that information to the eyes of whatever service provider you're using could violate your company's security policies.
So, Cubby encrypts your data at the source and only sends ciphertext up to the server. When you want to view the data, Cubby pulls down the ciphertext and uses a decryption key you provide to decrypt the data locally. As such, the name of "client X" was never exposed to Cubby's servers, keeping you safe if you need to mention confidential information.
The other problem of mine that Cubby solves is sharing. Sharing covers everything from sharing a password or cryptographic key with a single coworker to publishing a blog post to the entire world.
I've often felt that the mere inertia of blogging and the pressure to compile a suitable "blog"
to host my oeuvres often discouraged me from publishing my thoughts to the world. With Cubby,
any Markdown blob you store can be swiftly published with cubby publish put <blob name>
. A
unique URL is generated that you can share with the world, where readers can view your
(now-rendered) Markdown post in all its glory.
And the same applies for sharing secrets with other people. You can set a custom encryption
key for a blob containing a password with -K
and share it with your coworker using
cubby publish put -r <user email>
. As long as your coworker has a Cubby account and
you tell them the encryption passphrase you used (if any), they will be able to pull down
the ciphertext and decrypt it.
This base set of features lets me build all sorts of interesting little tools and workflows that make my job easier. It allows me to keep myself organized and provides me with a "cloud filesystem" of sorts that I can tightly integrate into existing scripts and workflows -- and one that, importantly, allows me to use the tools with which I'm most efficient.