Skip to content

Commit

Permalink
add support for creating projects
Browse files Browse the repository at this point in the history
  • Loading branch information
maxlaverse committed Nov 5, 2024
1 parent 6841212 commit fce2866
Show file tree
Hide file tree
Showing 16 changed files with 503 additions and 79 deletions.
39 changes: 39 additions & 0 deletions docs/resources/project.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "bitwarden_project Resource - terraform-provider-bitwarden"
subcategory: ""
description: |-
Manages a Project.
---

# bitwarden_project (Resource)

Manages a Project.

## Example Usage

```terraform
resource "bitwarden_project" "example" {
name = "Example Project"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name` (String) Name.

### Optional

- `id` (String) Identifier.
- `organization_id` (String) Identifier of the organization.

## Import

Import is supported using the following syntax:

```shell
$ terraform import bitwarden_project.example <project_id>
```
1 change: 1 addition & 0 deletions examples/resources/bitwarden_project/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$ terraform import bitwarden_project.example <project_id>
3 changes: 3 additions & 0 deletions examples/resources/bitwarden_project/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
resource "bitwarden_project" "example" {
name = "Example Project"
}
3 changes: 3 additions & 0 deletions internal/bitwarden/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ type PasswordManager interface {
}

type SecretsManager interface {
CreateProject(ctx context.Context, project models.Project) (*models.Project, error)
CreateSecret(ctx context.Context, secret models.Secret) (*models.Secret, error)
DeleteProject(ctx context.Context, project models.Project) error
DeleteSecret(ctx context.Context, secret models.Secret) error
EditProject(ctx context.Context, project models.Project) (*models.Project, error)
EditSecret(ctx context.Context, secret models.Secret) (*models.Secret, error)
GetProject(ctx context.Context, project models.Project) (*models.Project, error)
GetSecret(ctx context.Context, secret models.Secret) (*models.Secret, error)
Expand Down
90 changes: 84 additions & 6 deletions internal/bitwarden/embedded/secrets_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ import (
)

type SecretsManager interface {
CreateProject(ctx context.Context, project models.Project) (*models.Project, error)
CreateSecret(ctx context.Context, secret models.Secret) (*models.Secret, error)
DeleteProject(ctx context.Context, project models.Project) error
DeleteSecret(ctx context.Context, secret models.Secret) error
EditProject(ctx context.Context, project models.Project) (*models.Project, error)
EditSecret(ctx context.Context, secret models.Secret) (*models.Secret, error)
GetProject(ctx context.Context, project models.Project) (*models.Project, error)
GetSecret(ctx context.Context, secret models.Secret) (*models.Secret, error)
Expand Down Expand Up @@ -60,6 +63,33 @@ type secretsManager struct {
serverURL string
}

func (v *secretsManager) CreateProject(ctx context.Context, project models.Project) (*models.Project, error) {
if v.mainEncryptionKey == nil {
return nil, models.ErrLoggedOut
}

var resProject *models.Project

encProject, err := encryptProject(project, *v.mainEncryptionKey)
if err != nil {
return nil, fmt.Errorf("error encrypting project for creation: %w", err)
}
encProject.OrganizationID = v.mainOrganizationId

resEncProject, err := v.client.CreateProject(ctx, *encProject)

if err != nil {
return nil, fmt.Errorf("error creating project: %w", err)
}

resProject, err = decryptProject(*resEncProject, *v.mainEncryptionKey)
if err != nil {
return nil, fmt.Errorf("error decrypting project after creation: %w", err)
}

return resProject, nil
}

func (v *secretsManager) CreateSecret(ctx context.Context, secret models.Secret) (*models.Secret, error) {
if v.mainEncryptionKey == nil {
return nil, models.ErrLoggedOut
Expand Down Expand Up @@ -87,6 +117,15 @@ func (v *secretsManager) CreateSecret(ctx context.Context, secret models.Secret)
return resSecret, nil
}

func (v *secretsManager) DeleteProject(ctx context.Context, project models.Project) error {
err := v.client.DeleteProject(ctx, project.ID)
if err != nil {
return fmt.Errorf("error deleting project: %w", err)
}

return nil
}

func (v *secretsManager) DeleteSecret(ctx context.Context, secret models.Secret) error {
err := v.client.DeleteSecret(ctx, secret.ID)
if err != nil {
Expand All @@ -96,6 +135,32 @@ func (v *secretsManager) DeleteSecret(ctx context.Context, secret models.Secret)
return nil
}

func (v *secretsManager) EditProject(ctx context.Context, project models.Project) (*models.Project, error) {
if v.mainEncryptionKey == nil {
return nil, models.ErrLoggedOut
}

var resProject *models.Project

encProject, err := encryptProject(project, *v.mainEncryptionKey)
if err != nil {
return nil, fmt.Errorf("error encrypting project for edition: %w", err)
}

resEncProject, err := v.client.EditProject(ctx, *encProject)

if err != nil {
return nil, fmt.Errorf("error editing project: %w", err)
}

resProject, err = decryptProject(*resEncProject, *v.mainEncryptionKey)
if err != nil {
return nil, fmt.Errorf("error decrypting project after edition: %w", err)
}

return resProject, nil
}

func (v *secretsManager) EditSecret(ctx context.Context, secret models.Secret) (*models.Secret, error) {
if v.mainEncryptionKey == nil {
return nil, models.ErrLoggedOut
Expand Down Expand Up @@ -301,18 +366,31 @@ func decryptSecret[T SecretType](webapiSecret T, mainEncryptionKey symmetrickey.
}, nil
}

func decryptProject(webapiProject webapi.Project, mainEncryptionKey symmetrickey.Key) (*models.Project, error) {
projectName, err := decryptStringIfNotEmpty(webapiProject.Name, mainEncryptionKey)
func decryptProject(project models.Project, mainEncryptionKey symmetrickey.Key) (*models.Project, error) {
projectName, err := decryptStringIfNotEmpty(project.Name, mainEncryptionKey)
if err != nil {
return nil, fmt.Errorf("error decrypting project name: %w", err)
}

return &models.Project{
CreationDate: webapiProject.CreationDate,
ID: webapiProject.ID,
CreationDate: project.CreationDate,
ID: project.ID,
Name: projectName,
OrganizationID: project.OrganizationID,
RevisionDate: project.RevisionDate,
}, nil
}

func encryptProject(project models.Project, mainEncryptionKey symmetrickey.Key) (*models.Project, error) {
projectName, err := encryptAsStringIfNotEmpty(project.Name, mainEncryptionKey)
if err != nil {
return nil, fmt.Errorf("error encrypt project name: %w", err)
}

return &models.Project{
ID: project.ID,
Name: projectName,
OrganizationID: webapiProject.OrganizationID,
RevisionDate: webapiProject.RevisionDate,
OrganizationID: project.OrganizationID,
}, nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const (
ObjectCipherDetails ObjectType = "cipherDetails" // when creating attachment data
ObjectAttachmentFileUpload ObjectType = "attachment-fileUpload" // when creating attachment data
ObjectApiKey ObjectType = "api-key"
ObjectProject ObjectType = "project"
ObjectSecret ObjectType = "secret"
)

Expand Down
13 changes: 8 additions & 5 deletions internal/bitwarden/models/secrets_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ type Secret struct {
}

type Project struct {
ID string `json:"id"`
OrganizationID string `json:"organizationId"`
Name string `json:"name"`
CreationDate time.Time `json:"creationDate"`
RevisionDate time.Time `json:"revisionDate"`
ID string `json:"id,omitempty"`
OrganizationID string `json:"organizationId,omitempty"`
Name string `json:"name,omitempty"`
CreationDate time.Time `json:"creationDate,omitempty"`
RevisionDate time.Time `json:"revisionDate,omitempty"`
Read bool `json:"read,omitempty"`
Write bool `json:"write,omitempty"`
Object string `json:"object,omitempty"`
}
Loading

0 comments on commit fce2866

Please sign in to comment.