portwarden

package module
v0.0.0-...-2418138 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2023 License: MIT Imports: 24 Imported by: 0

README

Go Report Card

PortWarden

This project creates encrypted backups for Bitwarden vaults including attachments. It pulls your vault items from Bitwarden CLI and download all the attachments associated with those items to a temporary backup folder. Then, portwarden zip that folder, encrypt it with a passphrase, and delete the temporary folder.

It addresses this issue in the community forum https://community.bitwarden.com/t/encrypted-export/235, but hopefully Bitwarden will come up with official solutions soon.

3/28/20 Update

We now support restoring the backup to an empty account, including attachments.

Disclaimer

Note that you may lose your data if you try the restore feature and I am not responsible. Use the free software at your own discretion. Since we don't handle restoration conflicts, make sure to back up with your main account and restore to a spare/alternative account.

Usage Of Portwarden CLI

Go to https://github.com/bitwarden/cli/releases to download the latest version of Bitwarden CLI and place the executable bw/bw.exe in your PATH. Then, go to https://github.com/Sierra1011/portwarden/releases/ to download the latest release of portwarden. Now just follow these steps :

# If you are running self hosted instance, execute `bw config server https://MYSERVER.COM`
portwarden --passphrase 1234 --filename backup.portwarden encrypt
portwarden --passphrase 1234 --filename backup.portwarden decrypt
# RESTORE IS EXPERIMENTAL!! YOU MAY LOSE YOUR DATA
# IF YOU RESTORE TO YOUR MAIN ACCOUNT
# PLEASE MAKE SURE YOU KNOW WHAT YOU ARE DOING

# Please use a **spare** account for restoring backup
# Portwarden doesn't handle conflicts therefore a
# separate account is needed

# In fact we setup a check to make sure the account your
# are restoring to does not have any data in it
portwarden --passphrase 1234 --filename backup.portwarden restore
Demo Backup

alt text

Demo Decrypt

alt text

Demo restore

alt text

Portwarden Compared with Official Bitwarden Backup (As of 12/5/2018)

Portwarden Official Bitwarden Backup
Backend golang C#
Backup Format ✔ AES-Encrypted .portwarden format Unencrypted CSV file
Backup With Attachments Not supported (see this feature request)
Restore Attachments ✔ Supported Not supported

Contribution & Development

Clone this repo. Make sure you have Docker installed, ports 8000, 8081, 5000 unused, Golang installed, dep installed. In addition, create an environment varialble Salt of length 30 for encryption salt. Then run

dep ensure           # Install go dependencies
docker-compose up -d # Spin up required containers

# After the services/containers are created successfully, you should see
# $ docker-compose up  -d
# WARNING: Some services (worker) use the 'deploy' key, which will be ignored. Compose does not support 'deploy' configuration - use `docker stack deploy` to deploy to a swarm.
# Creating network "portwarden_default" with the default driver
# Creating portwarden_redis_1           ... done
# Creating portwarden_redis-commander_1 ... done
# Creating portwarden_frontend_1        ... done
# Creating portwarden_worker_1          ... done
# Creating portwarden_scheduler_1       ... done

docker ps # checkout the running containers
# $ docker ps
# CONTAINER ID        IMAGE                                   COMMAND                  CREATED             STATUS              PORTS                    NAMES
# e9bbc7263189        Sierra1011/portwarden-base:1.1.0           "/bin/bash"              15 seconds ago      Up 12 seconds       0.0.0.0:5000->5000/tcp   portwarden_scheduler_1
# f44247d80881        Sierra1011/portwarden-base:1.1.0           "go run main.go"         15 seconds ago      Up 12 seconds       5000/tcp                 portwarden_worker_1
# 37deb1556391        Sierra1011/portwarden-frontend:1.0.1       "/bin/sh -c 'npm run…"   17 seconds ago      Up 14 seconds       0.0.0.0:8000->8000/tcp   portwarden_frontend_1
# 6ab98b5515f1        redis                                   "docker-entrypoint.s…"   17 seconds ago      Up 14 seconds       0.0.0.0:6379->6379/tcp   portwarden_redis_1
# 78618bb157d2        rediscommander/redis-commander:latest   "/usr/bin/dumb-init …"   17 seconds ago      Up 14 seconds       0.0.0.0:8081->8081/tcp   portwarden_redis-commander_1

docker exec -it portwarden_scheduler_1 bash # get into scheduler container and do whatever you want.

# $ docker exec -it portwarden_scheduler_1 bash
# root@582b98fa1a25:/go/src/github.com/Sierra1011/portwarden/web/scheduler# go run main.go
# (string) (len=24) "Scheduler Server Started"
# [GIN-debug] [WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.

# [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

# [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
#  - using env:   export GIN_MODE=release
#  - using code:  gin.SetMode(gin.ReleaseMode)

# [GIN-debug] GET    /                         --> github.com/Sierra1011/portwarden/web/scheduler/server.(*PortwardenServer).Run.func1 (4 handlers)
# [GIN-debug] POST   /decrypt                  --> github.com/Sierra1011/portwarden/web/scheduler/server.DecryptBackupHandler (4 handlers)
# [GIN-debug] GET    /gdrive/loginUrl          --> github.com/Sierra1011/portwarden/web/scheduler/server.(*PortwardenServer).GetGoogleDriveLoginURLHandler-fm (4 handlers)
# [GIN-debug] GET    /gdrive/login             --> github.com/Sierra1011/portwarden/web/scheduler/server.(*PortwardenServer).GetGoogleDriveLoginHandler-fm (4 handlers)
# [GIN-debug] GET    /test/TokenAuthMiddleware --> github.com/Sierra1011/portwarden/web/scheduler/server.(*PortwardenServer).Run.func2 (5 handlers)
# [GIN-debug] POST   /encrypt                  --> github.com/Sierra1011/portwarden/web/scheduler/server.EncryptBackupHandler (5 handlers)
# [GIN-debug] POST   /encrypt/cancel           --> github.com/Sierra1011/portwarden/web/scheduler/server.CancelEncryptBackupHandler (5 handlers)
# [GIN-debug] Listening and serving HTTP on :5000

Notice the docker-compose.yaml file defines the services running and it's mounting your current directory as volumes and map it to the container's working directory. This means you can develop/make changes in your local machine, and run it in the container. It also maps certain containers' ports into your host so that you can call the endpoints.

PRs are welcome. For ideas, you could probably add a progress bar to the CLI.

Documentation

Overview

modified from https://www.thepolyglotdeveloper.com/2018/02/encrypt-decrypt-data-golang-application-crypto-packages/

Generated by https://quicktype.io

Index

Constants

View Source
const (
	BackupFolderName              = "./portwarden_backup/"
	ErrVaultIsLocked              = "vault is locked"
	ErrNoPhassPhraseProvided      = "no passphrase provided"
	ErrNoFilenameProvided         = "no filename provided"
	ErrSessionKeyExtractionFailed = "session key extraction failed"
	ErrVaultNotEmptyForRestore    = "account's valut not empty! you have to restore the backup to an empty Bitwarden account"

	BWErrNotLoggedIn           = "You are not logged in."
	BWErrInvalidMasterPassword = "Invalid master password."
	BWEnterEmailAddress        = "? Email address:"
	BWEnterMasterPassword      = "? Master password:"

	LoginCredentialMethodNone          = 100
	LoginCredentialMethodAuthenticator = 0
	LoginCredentialMethodEmail         = 1
	LoginCredentialMethodYubikey       = 3

	ItemsJsonFileName   = "items.json"
	FoldersJSONFileName = "folders.json"
)
View Source
const (
	ErrMessageAuthenticationFailed = "cipher: message authentication failed"
	ErrWrongBackupPassphrase       = "wrong backup passphrase entered"
)

Variables

This section is empty.

Functions

func BWDelete

func BWDelete(BITWARDENCLI_APPDATA_DIR string) error

func BWGetAllAttachments

func BWGetAllAttachments(outputDir, sessionKey string, pws []PortWardenElement, sleepMilliseconds int) error

func BWGetAttachment

func BWGetAttachment(outputDir, itemID, attachmentID, sessionKey string) error

func BWListFoldersRawBytes

func BWListFoldersRawBytes(sessionKey string) ([]byte, error)

func BWListItemsRawBytes

func BWListItemsRawBytes(sessionKey string) ([]byte, error)

func BWLoginGetSessionKey

func BWLoginGetSessionKey(lc *LoginCredentials) (string, error)

func BWLoginGetSessionKeyAndDataJSON

func BWLoginGetSessionKeyAndDataJSON(lc *LoginCredentials, BITWARDENCLI_APPDATA_DIR string) (string, []byte, error)

func BWLogout

func BWLogout() error

func CreateBackupBytes

func CreateBackupBytes(passphrase, sessionKey string, sleepMilliseconds int) ([]byte, error)

func CreateBackupBytesUsingBitwardenLocalJSON

func CreateBackupBytesUsingBitwardenLocalJSON(dataJson []byte, BITWARDENCLI_APPDATA_DIR, passphrase, sessionKey string, sleepMilliseconds int) ([]byte, error)

func CreateBackupFile

func CreateBackupFile(fileName, passphrase, sessionKey string, sleepMilliseconds int, noLogout bool) error

func DecryptBackupFile

func DecryptBackupFile(fileName, passphrase string) error

func DecryptBytes

func DecryptBytes(data []byte, passphrase string) ([]byte, error)

func DeriveKey

func DeriveKey(passphrase string) []byte

derive a key from the master password

func EncryptBytes

func EncryptBytes(data []byte, passphrase string) ([]byte, error)

func ExtractSessionKey

func ExtractSessionKey(stdout string) (string, error)

func RestoreBackupFile

func RestoreBackupFile(fileName, passphrase, sessionKey string, sleepMilliseconds int, noLogout bool) error

func Unzip

func Unzip(src, dest string) error

Types

type Attachment

type Attachment struct {
	ID       string `json:"id"`
	FileName string `json:"fileName"`
	Size     string `json:"size"`
	SizeName string `json:"sizeName"`
	URL      string `json:"url"`
}

type Card

type Card struct {
	CardholderName string  `json:"cardholderName"`
	Brand          string  `json:"brand"`
	Number         string  `json:"number"`
	ExpMonth       string  `json:"expMonth"`
	ExpYear        string  `json:"expYear"`
	Code           *string `json:"code"`
}

type Field

type Field struct {
	Name  *string `json:"name"`
	Value *string `json:"value"`
	Type  int64   `json:"type"`
}

type Identity

type Identity struct {
	Title          interface{} `json:"title"`
	FirstName      interface{} `json:"firstName"`
	MiddleName     interface{} `json:"middleName"`
	LastName       interface{} `json:"lastName"`
	Address1       interface{} `json:"address1"`
	Address2       interface{} `json:"address2"`
	Address3       interface{} `json:"address3"`
	City           interface{} `json:"city"`
	State          interface{} `json:"state"`
	PostalCode     interface{} `json:"postalCode"`
	Country        interface{} `json:"country"`
	Company        interface{} `json:"company"`
	Email          interface{} `json:"email"`
	Phone          interface{} `json:"phone"`
	Ssn            interface{} `json:"ssn"`
	Username       interface{} `json:"username"`
	PassportNumber interface{} `json:"passportNumber"`
	LicenseNumber  interface{} `json:"licenseNumber"`
}

type Login

type Login struct {
	Uris                 []Uris  `json:"uris"`
	Username             *string `json:"username"`
	Password             *string `json:"password"`
	Totp                 *string `json:"totp"`
	PasswordRevisionDate *string `json:"passwordRevisionDate"`
}

type LoginCredentials

type LoginCredentials struct {
	Email    string `json:"email"`
	Password string `json:"password"`
	Method   int    `json:"method"`
	Code     string `json:"code"`
}

LoginCredentials is used to login to the `bw` cli. See documentation https://help.bitwarden.com/article/cli/ The possible `Method` values are None 100 Authenticator 0 Email 1 Yubikey 3

type Object

type Object string
const (
	Folder Object = "folder"
)
const (
	Item Object = "item"
)

type PasswordHistory

type PasswordHistory struct {
	LastUsedDate string `json:"lastUsedDate"`
	Password     string `json:"password"`
}

type PortWarden

type PortWarden []PortWardenElement

type PortWardenElement

type PortWardenElement struct {
	Object          Object            `json:"object"`
	ID              string            `json:"id"`
	OrganizationID  *string           `json:"organizationId"`
	FolderID        *string           `json:"folderId"`
	Type            int64             `json:"type"`
	Name            string            `json:"name"`
	Notes           *string           `json:"notes"`
	Favorite        bool              `json:"favorite"`
	SecureNote      *SecureNote       `json:"secureNote,omitempty"`
	CollectionIDS   []string          `json:"collectionIds"`
	Attachments     []Attachment      `json:"attachments"`
	RevisionDate    string            `json:"revisionDate"`
	Login           *Login            `json:"login,omitempty"`
	PasswordHistory []PasswordHistory `json:"passwordHistory"`
	Fields          []Field           `json:"fields"`
	Card            *Card             `json:"card,omitempty"`
	Identity        *Identity         `json:"identity,omitempty"`
}

type PortWardenFolder

type PortWardenFolder []PortWardenFolderElement

type PortWardenFolderElement

type PortWardenFolderElement struct {
	Object Object  `json:"object"`
	ID     *string `json:"id"`
	Name   string  `json:"name"`
}

type SecureNote

type SecureNote struct {
	Type int64 `json:"type"`
}

type Uris

type Uris struct {
	Match interface{} `json:"match"`
	URI   string      `json:"uri"`
}

Directories

Path Synopsis
cmd
web

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL