diff --git a/api/api.go b/api/api.go index 601a358..8f94d7e 100644 --- a/api/api.go +++ b/api/api.go @@ -33,9 +33,14 @@ func (c *Client) DoCustomRequest(ctx context.Context, method, path, version stri // DoCustomRequestAndReturnRawResponse Executes a Custom Request and returns a APIResponse and the Raw HTTP Response func (c *Client) DoCustomRequestAndReturnRawResponse(ctx context.Context, method, path, version string, body interface{}, opts interface{}) (*http.Response, *APIResponse, error) { + // version is no longer used and is ignored. + return c.DoCustomRequestAndReturnRawResponseV5(ctx, method, path, body, opts) +} + +func (c *Client) DoCustomRequestAndReturnRawResponseV5(ctx context.Context, method, path string, body interface{}, opts interface{}) (*http.Response, *APIResponse, error) { firstTime := true start: - u, err := generateURL(*c.baseURL, path, version, opts) + u, err := generateURL(*c.baseURL, path, opts) if err != nil { return nil, nil, fmt.Errorf("Generating Path: %w", err) } diff --git a/api/auth.go b/api/auth.go index c3cbe83..406f81a 100644 --- a/api/auth.go +++ b/api/auth.go @@ -129,6 +129,12 @@ func (c *Client) Login(ctx context.Context) error { c.userPublicKey = user.GPGKey.ArmoredKey c.userID = user.ID + // after Login, fetch MetadataTypeSettings to finish the Client Setup + c.setMetadataTypeSettings(ctx) + if err != nil { + return fmt.Errorf("Setup Metadata Type Settings: %w", err) + } + return nil } diff --git a/api/client.go b/api/client.go index e08609f..001fce3 100644 --- a/api/client.go +++ b/api/client.go @@ -31,6 +31,9 @@ type Client struct { userPublicKey string userID string + // Server Settings Determining which Resource Types we can use + metadataTypeSettings MetadataTypeSettings + // used for solving MFA challenges. You can block this to for example wait for user input. // You shouden't run any unrelated API Calls while you are in this callback. // You need to Return the Cookie that Passbolt expects to verify you MFA, usually it is called passbolt_mfa @@ -169,17 +172,14 @@ func (c *Client) log(msg string, args ...interface{}) { fmt.Printf("[go-passbolt] "+msg+"\n", args...) } -func generateURL(base url.URL, p, version string, opt interface{}) (string, error) { +func generateURL(base url.URL, p string, opt interface{}) (string, error) { base.Path = path.Join(base.Path, p) - vs, err := query.Values(opt) if err != nil { return "", fmt.Errorf("Getting URL Query Values: %w", err) } - if version != "" { - vs.Add("api-version", version) - } base.RawQuery = vs.Encode() + return base.String(), nil } @@ -208,3 +208,26 @@ func (c *Client) GetPublicKey(ctx context.Context) (string, string, error) { } return body.Keydata, privateKeyObj.GetFingerprint(), nil } + +// setMetadataTypeSettings Gets and configures the Client to use the Types the Server wants us to use +func (c *Client) setMetadataTypeSettings(ctx context.Context) error { + settings, err := c.GetServerSettings(ctx) + if err != nil { + return fmt.Errorf("Getting Server Settings: %w", err) + } + + if settings.Passbolt.IsPluginEnabled("metadata") { + c.log("Server has metadata plugin enabled, is v5 or Higher") + metadataTypeSettings, err := c.GetMetadataTypeSettings(ctx) + if err != nil { + return fmt.Errorf("Getting Metadata Type Settings: %w", err) + } + + c.log("metadataTypeSettings: %+v", metadataTypeSettings) + c.metadataTypeSettings = *metadataTypeSettings + } else { + c.log("Server has metadata plugin disabled or not installed, Server is v4") + c.metadataTypeSettings = getV4DefaultMetadataTypeSettings() + } + return nil +} diff --git a/api/metadata_settings.go b/api/metadata_settings.go new file mode 100644 index 0000000..b54158f --- /dev/null +++ b/api/metadata_settings.go @@ -0,0 +1,73 @@ +package api + +import ( + "context" + "encoding/json" +) + +type PassboltAPIVersionType string + +const ( + PassboltAPIVersionTypeV4 PassboltAPIVersionType = "v4" + PassboltAPIVersionTypeV5 = "v5" +) + +func (s PassboltAPIVersionType) IsValid() bool { + switch s { + case PassboltAPIVersionTypeV4, PassboltAPIVersionTypeV5: + return true + } + return false +} + +// MetadataTypeSettings Contains the Servers Settings about which Types to use +type MetadataTypeSettings struct { + DefaultResourceType PassboltAPIVersionType `json:"default_resource_types"` + DefaultFolderType PassboltAPIVersionType `json:"default_folder_type"` + DefaultTagType PassboltAPIVersionType `json:"default_tag_type"` + DefaultCommentType PassboltAPIVersionType `json:"default_comment_type"` + AllowCreationOfV5Resources bool `json:"allow_creation_of_v5_resources"` + AllowCreationOfV5Folders bool `json:"allow_creation_of_v5_folders"` + AllowCreationOfV5Tags bool `json:"allow_creation_of_v5_tags"` + AllowCreationOfV5Comments bool `json:"allow_creation_of_v5_comments"` + AllowCreationOfV4Resources bool `json:"allow_creation_of_v4_resources"` + AllowCreationOfV4Folders bool `json:"allow_creation_of_v4_folders"` + AllowCreationOfV4Tags bool `json:"allow_creation_of_v4_tags"` + AllowCreationOfV4Comments bool `json:"allow_creation_of_v4_comments"` + AllowV4V5Upgrade bool `json:"allow_v4_v5_upgrade"` + AllowV4V5Downgrade bool `json:"allow_v5_v4_downgrade"` +} + +func getV4DefaultMetadataTypeSettings() MetadataTypeSettings { + return MetadataTypeSettings{ + DefaultResourceType: PassboltAPIVersionTypeV4, + DefaultFolderType: PassboltAPIVersionTypeV4, + DefaultTagType: PassboltAPIVersionTypeV4, + DefaultCommentType: PassboltAPIVersionTypeV4, + AllowCreationOfV5Resources: false, + AllowCreationOfV5Folders: false, + AllowCreationOfV5Tags: false, + AllowCreationOfV5Comments: false, + AllowCreationOfV4Resources: true, + AllowCreationOfV4Folders: true, + AllowCreationOfV4Tags: true, + AllowCreationOfV4Comments: true, + AllowV4V5Upgrade: false, + AllowV4V5Downgrade: false, + } +} + +// GetMetadataTypeSettings gets the Servers Settings about which Types to use +func (c *Client) GetMetadataTypeSettings(ctx context.Context) (*MetadataTypeSettings, error) { + msg, err := c.DoCustomRequest(ctx, "GET", "/metadata/types/settings.json", "v3", nil, nil) + if err != nil { + return nil, err + } + + var metadataSettings MetadataTypeSettings + err = json.Unmarshal(msg.Body, &metadataSettings) + if err != nil { + return nil, err + } + return &metadataSettings, nil +} diff --git a/api/settings.go b/api/settings.go new file mode 100644 index 0000000..4dd9260 --- /dev/null +++ b/api/settings.go @@ -0,0 +1,46 @@ +package api + +import ( + "context" + "encoding/json" +) + +// ServerSettingsResponse contains all Servers Settings +type ServerSettingsResponse struct { + Passbolt ServerPassboltSettings `json:"passbolt"` +} + +// ServerPassboltSettings contains Passbolt specific server settings +type ServerPassboltSettings struct { + Plugins map[string]ServerPassboltPluginSettings `json:"plugins"` +} + +// ServerPassboltPluginSettings contains the Settings of a Specific Passbolt Plugin +type ServerPassboltPluginSettings struct { + Enabled bool `json:"enabled"` + Version string `json:"version"` +} + +// GetServerSettings gets the Server Settings +func (c *Client) GetServerSettings(ctx context.Context) (*ServerSettingsResponse, error) { + msg, err := c.DoCustomRequest(ctx, "GET", "/settings.json", "v3", nil, nil) + if err != nil { + return nil, err + } + + var settings ServerSettingsResponse + err = json.Unmarshal(msg.Body, &settings) + if err != nil { + return nil, err + } + return &settings, nil +} + +func (ps *ServerPassboltSettings) IsPluginEnabled(name string) bool { + p, ok := ps.Plugins[name] + if !ok { + return false + } + + return p.Enabled +}