Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 193 additions & 0 deletions helper/resource_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package helper

import (
"context"
"encoding/json"
"fmt"

"github.com/passbolt/go-passbolt/api"
)

// CreateResource Creates a Resource, Creates a v4 or v5 Resources based on the server Preference
func CreateResource(ctx context.Context, c *api.Client, folderParentID, name, username, uri, password, description string) (string, error) {
// Create a v5 Password if that is the Server Default
if c.MetadataTypeSettings().DefaultResourceType == api.PassboltAPIVersionTypeV5 {
return CreateResourceV5(ctx, c, folderParentID, name, username, uri, password, description)
} else {
return CreateResourceV4(ctx, c, folderParentID, name, username, uri, password, description)
}
}

func CreateResourceV5(ctx context.Context, c *api.Client, folderParentID, name, username, uri, password, description string) (string, error) {
if c.MetadataTypeSettings().AllowCreationOfV5Resources == false {
return "", fmt.Errorf("Creation of V5 Passwords is disabled on this Server")
}

types, err := c.GetResourceTypes(ctx, nil)
if err != nil {
return "", fmt.Errorf("Getting ResourceTypes: %w", err)
}
var rType *api.ResourceType
for _, tmp := range types {
if tmp.Slug == "v5-default" {
rType = &tmp
break
}
}
if rType == nil {
return "", fmt.Errorf("Cannot find Resource type password-and-description")
}

// Base Resource
resource := api.Resource{
ResourceTypeID: rType.ID,
FolderParentID: folderParentID,
}

// Resource Metadata
meta := api.ResourceMetadataTypeV5Default{
ObjectType: api.PASSBOLT_OBJECT_TYPE_RESOURCE_METADATA,
ResourceTypeID: rType.ID,
Name: name,
Username: username,
URIs: []string{uri},
}

metaData, err := json.Marshal(&meta)
if err != nil {
return "", fmt.Errorf("Marshalling metadata: %w", err)
}

err = validateMetadata(rType, string(metaData))
if err != nil {
return "", fmt.Errorf("Validating metadata: %w", err)
}

metadataKeyID, metadataKeyType, publicMetadataKey, err := GetMetadataKey(ctx, c, true)
if err != nil {
return "", fmt.Errorf("Get Metadata Key: %w", err)
}
resource.MetadataKeyID = metadataKeyID
resource.MetadataKeyType = metadataKeyType

encMetadata, err := c.EncryptMessageWithKey(publicMetadataKey, string(metaData))
if err != nil {
return "", fmt.Errorf("Encrypt Metadata: %w", err)
}
resource.Metadata = encMetadata

// Resource Secret
secret := api.SecretDataTypeV5Default{
ObjectType: api.PASSBOLT_OBJECT_TYPE_SECRET_DATA,
Password: password,
Description: description,
}

secretData, err := json.Marshal(&secret)
if err != nil {
return "", fmt.Errorf("Marshalling Secret Data: %w", err)
}

err = validateSecretData(rType, string(secretData))
if err != nil {
return "", fmt.Errorf("Validating Secret Data: %w", err)
}

encSecretData, err := c.EncryptMessage(string(secretData))
if err != nil {
return "", fmt.Errorf("Encrypting Secret Data for User me: %w", err)
}
resource.Secrets = []api.Secret{{Data: encSecretData}}

newresource, err := c.CreateResource(ctx, resource)
if err != nil {
return "", fmt.Errorf("Creating Resource: %w", err)
}
return newresource.ID, nil
}

func CreateResourceV4(ctx context.Context, c *api.Client, folderParentID, name, username, uri, password, description string) (string, error) {
if c.MetadataTypeSettings().AllowCreationOfV4Resources == false {
return "", fmt.Errorf("Creation of V4 Passwords is disabled on this Server")
}

types, err := c.GetResourceTypes(ctx, nil)
if err != nil {
return "", fmt.Errorf("Getting ResourceTypes: %w", err)
}
var rType *api.ResourceType
for _, tmp := range types {
if tmp.Slug == "password-and-description" {
rType = &tmp
break
}
}
if rType == nil {
return "", fmt.Errorf("Cannot find Resource type password-and-description")
}

resource := api.Resource{
ResourceTypeID: rType.ID,
FolderParentID: folderParentID,
Name: name,
Username: username,
URI: uri,
}

tmp := api.SecretDataTypePasswordAndDescription{
Password: password,
Description: description,
}
secretData, err := json.Marshal(&tmp)
if err != nil {
return "", fmt.Errorf("Marshalling Secret Data: %w", err)
}

err = validateSecretData(rType, string(secretData))
if err != nil {
return "", fmt.Errorf("Validating Secret Data: %w", err)
}

encSecretData, err := c.EncryptMessage(string(secretData))
if err != nil {
return "", fmt.Errorf("Encrypting Secret Data for User me: %w", err)
}
resource.Secrets = []api.Secret{{Data: encSecretData}}

newresource, err := c.CreateResource(ctx, resource)
if err != nil {
return "", fmt.Errorf("Creating Resource: %w", err)
}
return newresource.ID, nil
}

// CreateResourceSimple Creates a Legacy Resource where only the Password is Encrypted and Returns the Resources ID
func CreateResourceSimple(ctx context.Context, c *api.Client, folderParentID, name, username, uri, password, description string) (string, error) {
if c.MetadataTypeSettings().AllowCreationOfV4Resources == false {
return "", fmt.Errorf("Creation of V4 Passwords is disabled on this Server")
}

// TODO Create a v5-password-string if v5 is enabled

enc, err := c.EncryptMessage(password)
if err != nil {
return "", fmt.Errorf("Encrypting Password: %w", err)
}

res := api.Resource{
Name: name,
URI: uri,
Username: username,
FolderParentID: folderParentID,
Description: description,
Secrets: []api.Secret{
{Data: enc},
},
}

resource, err := c.CreateResource(ctx, res)
if err != nil {
return "", fmt.Errorf("Creating Resource: %w", err)
}
return resource.ID, nil
}
181 changes: 181 additions & 0 deletions helper/resource_get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package helper

import (
"context"
"encoding/json"
"fmt"

"github.com/passbolt/go-passbolt/api"
)

// GetResource Gets a Resource by ID
func GetResource(ctx context.Context, c *api.Client, resourceID string) (folderParentID, name, username, uri, password, description string, err error) {
resource, err := c.GetResource(ctx, resourceID)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Getting Resource: %w", err)
}

rType, err := c.GetResourceType(ctx, resource.ResourceTypeID)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Getting ResourceType: %w", err)
}
secret, err := c.GetSecret(ctx, resource.ID)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Getting Resource Secret: %w", err)
}
return GetResourceFromData(c, *resource, *secret, *rType)
}

// GetResourceFromData Decrypts Resources using only local data, the Resource object must inlude the secret
// With v5 This needs network calls for Metadata of v5 Resources
func GetResourceFromData(c *api.Client, resource api.Resource, secret api.Secret, rType api.ResourceType) (string, string, string, string, string, string, error) {
var name string
var username string
var uri string
var pw string
var desc string

ctx := context.TODO()

switch rType.Slug {
case "password-string":
var err error
pw, err = c.DecryptMessage(secret.Data)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Decrypting Secret Data: %w", err)
}
name = resource.Name
username = resource.Username
uri = resource.URI
desc = resource.Description
case "password-and-description":
rawSecretData, err := c.DecryptMessage(secret.Data)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Decrypting Secret Data: %w", err)
}

var secretData api.SecretDataTypePasswordAndDescription
err = json.Unmarshal([]byte(rawSecretData), &secretData)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Secret Data: %w", err)
}
name = resource.Name
username = resource.Username
uri = resource.URI
pw = secretData.Password
desc = secretData.Description
case "password-description-totp":
rawSecretData, err := c.DecryptMessage(secret.Data)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Decrypting Secret Data: %w", err)
}

var secretData api.SecretDataTypePasswordDescriptionTOTP
err = json.Unmarshal([]byte(rawSecretData), &secretData)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Secret Data: %w", err)
}
name = resource.Name
username = resource.Username
uri = resource.URI
pw = secretData.Password
desc = secretData.Description
case "totp":
name = resource.Name
username = resource.Username
uri = resource.URI
// nothing fits into the interface in this case
case "v5-default":
rawMetadata, err := GetResourceMetadata(ctx, c, &resource, &rType)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Getting Metadata: %w", err)
}

var metadata api.ResourceMetadataTypeV5Default
err = json.Unmarshal([]byte(rawMetadata), &metadata)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Metadata: %w", err)
}

name = metadata.Name
username = metadata.Username
if len(metadata.URIs) != 0 {
uri = metadata.URIs[0]
}

rawSecretData, err := c.DecryptMessage(secret.Data)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Decrypting Secret Data: %w", err)
}

var secretData api.SecretDataTypeV5Default
err = json.Unmarshal([]byte(rawSecretData), &secretData)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Secret Data: %w", err)
}
pw = secretData.Password
desc = secretData.Description
case "v5-default-with-totp":
rawMetadata, err := GetResourceMetadata(ctx, c, &resource, &rType)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Getting Metadata: %w", err)
}

var metadata api.ResourceMetadataTypeV5DefaultWithTOTP
err = json.Unmarshal([]byte(rawMetadata), &metadata)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Metadata: %w", err)
}

name = metadata.Name
username = metadata.Username
if len(metadata.URIs) != 0 {
uri = metadata.URIs[0]
}

rawSecretData, err := c.DecryptMessage(secret.Data)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Decrypting Secret Data: %w", err)
}

var secretData api.SecretDataTypeV5DefaultWithTOTP
err = json.Unmarshal([]byte(rawSecretData), &secretData)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Secret Data: %w", err)
}
pw = secretData.Password
desc = secretData.Description
case "v5-password-string":
rawMetadata, err := GetResourceMetadata(ctx, c, &resource, &rType)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Getting Metadata: %w", err)
}

var metadata api.ResourceMetadataTypeV5PasswordString
err = json.Unmarshal([]byte(rawMetadata), &metadata)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Metadata: %w", err)
}

name = metadata.Name
username = metadata.Username
if len(metadata.URIs) != 0 {
uri = metadata.URIs[0]
}

// Not available in the Secret
desc = metadata.Description

rawSecretData, err := c.DecryptMessage(secret.Data)
if err != nil {
return "", "", "", "", "", "", fmt.Errorf("Decrypting Secret Data: %w", err)
}

pw = rawSecretData
case "v5-totp-standalone":
// nothing fits into the interface in this case
default:
return "", "", "", "", "", "", fmt.Errorf("Unknown ResourceType: %v", rType.Slug)
}
return resource.FolderParentID, name, username, uri, pw, desc, nil
}
Loading