package entries import "time" const bitwardenLoginItemType = 1 // BitwardenExport represents Bitwarden's plaintext JSON vault export format. // MaxWarden does not have folders, so every item is exported at the vault root. type BitwardenExport struct { Encrypted bool `json:"encrypted"` Folders []any `json:"folders"` Items []BitwardenItem `json:"items"` } type BitwardenItem struct { PasswordHistory []any `json:"passwordHistory"` RevisionDate string `json:"revisionDate"` CreationDate string `json:"creationDate"` DeletedDate *string `json:"deletedDate"` ID string `json:"id"` OrganizationID *string `json:"organizationId"` FolderID *string `json:"folderId"` Type int `json:"type"` Reprompt int `json:"reprompt"` Name string `json:"name"` Notes string `json:"notes"` Favorite bool `json:"favorite"` Login BitwardenLogin `json:"login"` CollectionIDs []string `json:"collectionIds"` } type BitwardenLogin struct { URIs []BitwardenURI `json:"uris"` Username string `json:"username"` Password string `json:"password"` TOTP *string `json:"totp"` } type BitwardenURI struct { Match *int `json:"match"` URI string `json:"uri"` } func NewBitwardenExport(secrets []Secret) BitwardenExport { items := make([]BitwardenItem, 0, len(secrets)) for _, secret := range secrets { uris := make([]BitwardenURI, 0, 1) if secret.URL != "" { uris = append(uris, BitwardenURI{URI: secret.URL}) } items = append(items, BitwardenItem{ PasswordHistory: nil, RevisionDate: bitwardenTime(secret.Modified), CreationDate: bitwardenTime(secret.Created), ID: secret.ID, Type: bitwardenLoginItemType, Reprompt: 0, Name: secret.Description, Notes: secret.Notes, Favorite: false, Login: BitwardenLogin{ URIs: uris, Username: secret.Username, Password: secret.Password, }, CollectionIDs: nil, }) } return BitwardenExport{ Encrypted: false, Folders: make([]any, 0), Items: items, } } func bitwardenTime(value time.Time) string { if value.IsZero() { return "" } return value.UTC().Format(time.RFC3339Nano) }