mirror of
https://github.com/passbolt/go-passbolt.git
synced 2025-05-07 17:08:21 +00:00
Move code from Internal Git
This commit is contained in:
parent
4457df3e5f
commit
ff29c83d56
26 changed files with 2008 additions and 0 deletions
57
api.go
Normal file
57
api.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// APIResponse is the Struct representation of a Json Response
|
||||
type APIResponse struct {
|
||||
Header APIHeader `json:"header"`
|
||||
Body json.RawMessage `json:"body"`
|
||||
}
|
||||
|
||||
// APIHeader is the Struct representation of the Header of a APIResponse
|
||||
type APIHeader struct {
|
||||
ID string `json:"id"`
|
||||
Status string `json:"status"`
|
||||
Servertime int `json:"servertime"`
|
||||
Action string `json:"action"`
|
||||
Message string `json:"message"`
|
||||
URL string `json:"url"`
|
||||
Code int `json:"code"`
|
||||
}
|
||||
|
||||
// DoCustomRequest Executes a Custom Request and returns a APIResponse
|
||||
func (c *Client) DoCustomRequest(ctx context.Context, method, path, version string, body interface{}, opts interface{}) (*APIResponse, error) {
|
||||
_, response, err := c.DoCustomRequestAndReturnRawResponse(ctx, method, path, version, body, opts)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func (c *Client) DoCustomRequestAndReturnRawResponse(ctx context.Context, method, path, version string, body interface{}, opts interface{}) (*http.Response, *APIResponse, error) {
|
||||
u, err := addOptions(path, version, opts)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Adding Request Options: %w", err)
|
||||
}
|
||||
|
||||
req, err := c.newRequest(method, u, body)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Creating New Request: %w", err)
|
||||
}
|
||||
|
||||
var res APIResponse
|
||||
r, err := c.do(ctx, req, &res)
|
||||
if err != nil {
|
||||
return r, &res, fmt.Errorf("Doing Request: %w", err)
|
||||
}
|
||||
|
||||
if res.Header.Status == "success" {
|
||||
return r, &res, nil
|
||||
} else if res.Header.Status == "error" {
|
||||
return r, &res, fmt.Errorf("%w: Message: %v, Body: %v", ErrAPIResponseErrorStatusCode, res.Header.Message, string(res.Body))
|
||||
} else {
|
||||
return r, &res, fmt.Errorf("%w: Message: %v, Body: %v", ErrAPIResponseUnknownStatusCode, res.Header.Message, string(res.Body))
|
||||
}
|
||||
}
|
206
auth.go
Normal file
206
auth.go
Normal file
|
@ -0,0 +1,206 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
||||
"github.com/ProtonMail/gopenpgp/v2/helper"
|
||||
)
|
||||
|
||||
// PublicKeyReponse the Body of a Public Key Api Request
|
||||
type PublicKeyReponse struct {
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
Keydata string `json:"keydata"`
|
||||
}
|
||||
|
||||
// Login is used for login
|
||||
type Login struct {
|
||||
Auth *GPGAuth `json:"gpg_auth"`
|
||||
}
|
||||
|
||||
// GPGAuth is used for login
|
||||
type GPGAuth struct {
|
||||
KeyID string `json:"keyid"`
|
||||
Token string `json:"user_token_result,omitempty"`
|
||||
}
|
||||
|
||||
// TODO add Server Verification Function
|
||||
|
||||
// GetPublicKey gets the Public Key and Fingerprint of the Passbolt instance
|
||||
func (c *Client) GetPublicKey(ctx context.Context) (string, string, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "auth/verify.json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Doing Request: %w", err)
|
||||
}
|
||||
|
||||
var body PublicKeyReponse
|
||||
err = json.Unmarshal(msg.Body, &body)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Parsing JSON: %w", err)
|
||||
}
|
||||
// TODO check if that Fingerpirnt is actually from the Publickey
|
||||
return body.Keydata, body.Fingerprint, nil
|
||||
}
|
||||
|
||||
// CheckSession Check to see if you have a Valid Session
|
||||
func (c *Client) CheckSession(ctx context.Context) bool {
|
||||
_, err := c.DoCustomRequest(ctx, "GET", "auth/is-authenticated.json", "v2", nil, nil)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// Login gets a Session and CSRF Token from Passbolt and Stores them in the Clients Cookie Jar
|
||||
func (c *Client) Login(ctx context.Context) error {
|
||||
|
||||
privateKeyObj, err := crypto.NewKeyFromArmored(c.userPrivateKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Parsing User Private Key: %w", err)
|
||||
}
|
||||
data := Login{&GPGAuth{KeyID: privateKeyObj.GetFingerprint()}}
|
||||
|
||||
res, _, err := c.DoCustomRequestAndReturnRawResponse(ctx, "POST", "/auth/login.json", "v2", data, nil)
|
||||
if err != nil && !strings.Contains(err.Error(), "Error API JSON Response Status: Message: The authentication failed.") {
|
||||
return fmt.Errorf("Doing Stage 1 Request: %w", err)
|
||||
}
|
||||
|
||||
encAuthToken := res.Header.Get("X-GPGAuth-User-Auth-Token")
|
||||
|
||||
if encAuthToken == "" {
|
||||
return fmt.Errorf("Got Empty X-GPGAuth-User-Auth-Token Header")
|
||||
}
|
||||
|
||||
c.log("Got Encrypted Auth Token: %v", encAuthToken)
|
||||
|
||||
encAuthToken, err = url.QueryUnescape(encAuthToken)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unescaping User Auth Token: %w", err)
|
||||
}
|
||||
encAuthToken = strings.ReplaceAll(encAuthToken, "\\ ", " ")
|
||||
|
||||
authToken, err := helper.DecryptMessageArmored(c.userPrivateKey, c.userPassword, encAuthToken)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Decrypting User Auth Token: %w", err)
|
||||
}
|
||||
|
||||
c.log("Decrypted Auth Token: %v", authToken)
|
||||
|
||||
err = checkAuthTokenFormat(authToken)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Checking Auth Token Format: %w", err)
|
||||
}
|
||||
|
||||
data.Auth.Token = string(authToken)
|
||||
|
||||
res, _, err = c.DoCustomRequestAndReturnRawResponse(ctx, "POST", "/auth/login.json", "v2", data, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Doing Stage 2 Request: %w", err)
|
||||
}
|
||||
|
||||
c.log("Got Cookies: %+v", res.Cookies())
|
||||
|
||||
for _, cookie := range res.Cookies() {
|
||||
if cookie.Name == "passbolt_session" {
|
||||
c.sessionToken = *cookie
|
||||
// Session Cookie in older Passbolt Versions
|
||||
} else if cookie.Name == "CAKEPHP" {
|
||||
c.sessionToken = *cookie
|
||||
}
|
||||
}
|
||||
if c.sessionToken.Name == "" {
|
||||
return fmt.Errorf("Cannot Find Session Cookie!")
|
||||
}
|
||||
|
||||
// Do Mfa Here if ever
|
||||
|
||||
// You have to get a make GET Request to get the CSRF Token which is Required for Write Operations
|
||||
msg, apiMsg, err := c.DoCustomRequestAndReturnRawResponse(ctx, "GET", "/users/me.json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
c.log("is MFA Enabled? That is not yet Supported!")
|
||||
return fmt.Errorf("Getting CSRF Token: %w", err)
|
||||
}
|
||||
|
||||
for _, cookie := range msg.Cookies() {
|
||||
if cookie.Name == "csrfToken" {
|
||||
c.csrfToken = *cookie
|
||||
}
|
||||
}
|
||||
|
||||
if c.csrfToken.Name == "" {
|
||||
return fmt.Errorf("Cannot Find csrfToken Cookie!")
|
||||
}
|
||||
|
||||
// Get Users Own Public Key from Server
|
||||
var user User
|
||||
err = json.Unmarshal(apiMsg.Body, &user)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Parsing User 'Me' JSON from API Request: %w", err)
|
||||
}
|
||||
|
||||
// Validate that this Publickey that the Server gave us actually Matches our Privatekey
|
||||
randomString, err := randStringBytesRmndr(50)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Generating Random String as PublicKey Validation Message: %w", err)
|
||||
}
|
||||
armor, err := helper.EncryptMessageArmored(user.GPGKey.ArmoredKey, randomString)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Encryping PublicKey Validation Message: %w", err)
|
||||
}
|
||||
decrypted, err := helper.DecryptMessageArmored(c.userPrivateKey, c.userPassword, armor)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Decrypting PublicKey Validation Message (you might be getting Hacked): %w", err)
|
||||
}
|
||||
if decrypted != randomString {
|
||||
return fmt.Errorf("Decrypted PublicKey Validation Message does not Match Original (you might be getting Hacked): %w", err)
|
||||
}
|
||||
|
||||
// Insert PublicKey into Client after checking it to Prevent ignored errors leading to proceding with a potentially Malicious PublicKey
|
||||
c.userPublicKey = user.GPGKey.ArmoredKey
|
||||
c.userID = user.ID
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Logout closes the current Session on the Passbolt server
|
||||
func (c *Client) Logout(ctx context.Context) error {
|
||||
_, err := c.DoCustomRequest(ctx, "GET", "/auth/logout.json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Doing Logout Request: %w", err)
|
||||
}
|
||||
c.sessionToken = http.Cookie{}
|
||||
c.csrfToken = http.Cookie{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) GetUserID() string {
|
||||
return c.userID
|
||||
}
|
||||
|
||||
func checkAuthTokenFormat(authToken string) error {
|
||||
splitAuthToken := strings.Split(authToken, "|")
|
||||
if len(splitAuthToken) != 4 {
|
||||
return fmt.Errorf("Auth Token Has Wrong amount of Fields")
|
||||
}
|
||||
|
||||
if splitAuthToken[0] != splitAuthToken[3] {
|
||||
return fmt.Errorf("Auth Token Version Fields Don't match")
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(splitAuthToken[0], "gpgauth") {
|
||||
return fmt.Errorf("Auth Token Version does not start with 'gpgauth'")
|
||||
}
|
||||
|
||||
length, err := strconv.Atoi(splitAuthToken[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot Convert Auth Token Length Field to int: %w", err)
|
||||
}
|
||||
|
||||
if len(splitAuthToken[2]) != length {
|
||||
return fmt.Errorf("Auth Token Data Length does not Match Length Field")
|
||||
}
|
||||
return nil
|
||||
}
|
152
client.go
Normal file
152
client.go
Normal file
|
@ -0,0 +1,152 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
||||
"github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
// Client is a Client struct for the Passbolt api
|
||||
type Client struct {
|
||||
baseURL *url.URL
|
||||
userAgent string
|
||||
httpClient *http.Client
|
||||
|
||||
sessionToken http.Cookie
|
||||
csrfToken http.Cookie
|
||||
|
||||
// for some reason []byte is used for Passwords in gopenpgp instead of string like they do for keys...
|
||||
userPassword []byte
|
||||
userPrivateKey string
|
||||
userPublicKey string
|
||||
userID string
|
||||
|
||||
// Enable Debug Logging
|
||||
Debug bool
|
||||
}
|
||||
|
||||
// NewClient Returns a new Passbolt Client
|
||||
func NewClient(BaseURL *url.URL, httpClient *http.Client, UserAgent, UserPrivateKey, UserPassword string) (*Client, error) {
|
||||
if httpClient == nil {
|
||||
httpClient = http.DefaultClient
|
||||
}
|
||||
if UserAgent == "" {
|
||||
UserAgent = "goPassboltClient/1.0"
|
||||
}
|
||||
|
||||
// Verify that the Given Privatekey and Password are valid and work Together
|
||||
privateKeyObj, err := crypto.NewKeyFromArmored(UserPrivateKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to Create Key From UserPrivateKey string: %w", err)
|
||||
}
|
||||
unlockedKeyObj, err := privateKeyObj.Unlock([]byte(UserPassword))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to Unlock UserPrivateKey using UserPassword: %w", err)
|
||||
}
|
||||
privateKeyRing, err := crypto.NewKeyRing(unlockedKeyObj)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to Create a new Key Ring using the unlocked UserPrivateKey: %w", err)
|
||||
}
|
||||
|
||||
// Cleanup Secrets
|
||||
privateKeyRing.ClearPrivateParams()
|
||||
|
||||
// Create Client Object
|
||||
c := &Client{
|
||||
httpClient: httpClient,
|
||||
baseURL: BaseURL,
|
||||
userAgent: UserAgent,
|
||||
userPassword: []byte(UserPassword),
|
||||
userPrivateKey: UserPrivateKey,
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(method, path string, body interface{}) (*http.Request, error) {
|
||||
rel, err := url.Parse(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Parsing URL: %w", err)
|
||||
}
|
||||
u := c.baseURL.ResolveReference(rel)
|
||||
var buf io.ReadWriter
|
||||
if body != nil {
|
||||
buf = new(bytes.Buffer)
|
||||
err := json.NewEncoder(buf).Encode(body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("JSON Encoding Request: %w", err)
|
||||
}
|
||||
}
|
||||
req, err := http.NewRequest(method, u.String(), buf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Creating HTTP Request: %w", err)
|
||||
}
|
||||
if body != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("User-Agent", c.userAgent)
|
||||
req.Header.Set("X-CSRF-Token", c.csrfToken.Value)
|
||||
req.AddCookie(&c.sessionToken)
|
||||
req.AddCookie(&c.csrfToken)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (c *Client) do(ctx context.Context, req *http.Request, v *APIResponse) (*http.Response, error) {
|
||||
req = req.WithContext(ctx)
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, fmt.Errorf("Request Context: %w", ctx.Err())
|
||||
default:
|
||||
return nil, fmt.Errorf("Request: %w", err)
|
||||
}
|
||||
}
|
||||
defer func() {
|
||||
resp.Body.Close()
|
||||
}()
|
||||
|
||||
bodyBytes, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("Error Reading Resopnse Body: %w", err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(bodyBytes, v)
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("Unable to Parse JSON API Response with HTTP Status Code %v: %w", resp.StatusCode, err)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *Client) log(msg string, args ...interface{}) {
|
||||
if !c.Debug {
|
||||
return
|
||||
}
|
||||
fmt.Printf("[go-passbolt] "+msg+"\n", args...)
|
||||
}
|
||||
|
||||
func addOptions(s, version string, opt interface{}) (string, error) {
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return s, fmt.Errorf("Parsing URL: %w", err)
|
||||
}
|
||||
|
||||
vs, err := query.Values(opt)
|
||||
if err != nil {
|
||||
return s, fmt.Errorf("Getting URL Query Values: %w", err)
|
||||
}
|
||||
if version != "" {
|
||||
vs.Add("api-version", version)
|
||||
}
|
||||
u.RawQuery = vs.Encode()
|
||||
return u.String(), nil
|
||||
}
|
80
comments.go
Normal file
80
comments.go
Normal file
|
@ -0,0 +1,80 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Comment is a Comment
|
||||
type Comment struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
ParentID string `json:"parent_id,omitempty"`
|
||||
ForeignKey string `json:"foreign_key,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
ForeignModel string `json:"foreign_model,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
CreatedBy string `json:"created_by,omitempty"`
|
||||
UserID string `json:"user_id,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
ModifiedBy string `json:"modified_by,omitempty"`
|
||||
Children []Comment `json:"children,omitempty"`
|
||||
}
|
||||
|
||||
// GetCommentsOptions are all available query parameters
|
||||
type GetCommentsOptions struct {
|
||||
ContainCreator bool `url:"contain[creator],omitempty"`
|
||||
ContainModifier bool `url:"contain[modifier],omitempty"`
|
||||
}
|
||||
|
||||
// GetComments gets all Passbolt Comments an The Specified Resource
|
||||
func (c *Client) GetComments(ctx context.Context, resourceID string, opts *GetCommentsOptions) ([]Comment, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/comments/resource/"+resourceID+".json", "v2", nil, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var comments []Comment
|
||||
err = json.Unmarshal(msg.Body, &comments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return comments, nil
|
||||
}
|
||||
|
||||
// CreateComment Creates a new Passbolt Comment
|
||||
func (c *Client) CreateComment(ctx context.Context, resourceID string, comment Comment) (*Comment, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "POST", "/comments/resource/"+resourceID+".json", "v2", comment, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(msg.Body, &comment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &comment, nil
|
||||
}
|
||||
|
||||
// UpdateComment Updates a existing Passbolt Comment
|
||||
func (c *Client) UpdateComment(ctx context.Context, commentID string, comment Comment) (*Comment, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "PUT", "/comments/"+commentID+".json", "v2", comment, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(msg.Body, &comment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &comment, nil
|
||||
}
|
||||
|
||||
// DeleteComment Deletes a Passbolt Comment
|
||||
func (c *Client) DeleteComment(ctx context.Context, commentID string) error {
|
||||
_, err := c.DoCustomRequest(ctx, "DELETE", "/comments/"+commentID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
20
encryption.go
Normal file
20
encryption.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package passbolt
|
||||
|
||||
import "github.com/ProtonMail/gopenpgp/v2/helper"
|
||||
|
||||
// EncryptMessage encrypts a message using the users public key and then signes the message using the users private key
|
||||
func (c *Client) EncryptMessage(message string) (string, error) {
|
||||
return helper.EncryptSignMessageArmored(c.userPublicKey, c.userPrivateKey, c.userPassword, message)
|
||||
}
|
||||
|
||||
// EncryptMessageWithPublicKey encrypts a message using the provided public key and then signes the message using the users private key
|
||||
func (c *Client) EncryptMessageWithPublicKey(publickey, message string) (string, error) {
|
||||
return helper.EncryptSignMessageArmored(publickey, c.userPrivateKey, c.userPassword, message)
|
||||
}
|
||||
|
||||
// DecryptMessage decrypts a message using the users Private Key and Validates its Signature using the users public key
|
||||
func (c *Client) DecryptMessage(message string) (string, error) {
|
||||
// We cant Verify the signature as we don't store other users public keys locally and don't know which user did encrypt it
|
||||
//return helper.DecryptVerifyMessageArmored(c.userPublicKey, c.userPrivateKey, c.userPassword, message)
|
||||
return helper.DecryptMessageArmored(c.userPrivateKey, c.userPassword, message)
|
||||
}
|
8
errors.go
Normal file
8
errors.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package passbolt
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrAPIResponseErrorStatusCode = errors.New("Error API JSON Response Status")
|
||||
ErrAPIResponseUnknownStatusCode = errors.New("Unknown API JSON Response Status")
|
||||
)
|
39
favorites.go
Normal file
39
favorites.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Favorite is a Favorite
|
||||
type Favorite struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
ForeignKey string `json:"foreign_key,omitempty"`
|
||||
ForeignModel string `json:"foreign_model,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
}
|
||||
|
||||
// CreateFavorite Creates a new Passbolt Favorite for the given Resource ID
|
||||
func (c *Client) CreateFavorite(ctx context.Context, resourceID string) (*Favorite, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "POST", "/favorites/resource/"+resourceID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var favorite Favorite
|
||||
err = json.Unmarshal(msg.Body, &favorite)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &favorite, nil
|
||||
}
|
||||
|
||||
// DeleteFavorite Deletes a Passbolt Favorite
|
||||
func (c *Client) DeleteFavorite(ctx context.Context, favoriteID string) error {
|
||||
_, err := c.DoCustomRequest(ctx, "DELETE", "/favorites/"+favoriteID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
117
folders.go
Normal file
117
folders.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Folder is a Folder
|
||||
type Folder struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
CreatedBy string `json:"created_by,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
ModifiedBy string `json:"modified_by,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Permissions []Permission `json:"permissions,omitempty"`
|
||||
FolderParentID string `json:"folder_parent_id,omitempty"`
|
||||
Personal bool `json:"personal,omitempty"`
|
||||
ChildrenResources []Resource `json:"children_resources,omitempty"`
|
||||
ChildrenFolders []Folder `json:"children_folders,omitempty"`
|
||||
}
|
||||
|
||||
// GetFolderOptions are all available query parameters
|
||||
type GetFolderOptions struct {
|
||||
ContainChildrenResources bool `url:"contain[children_resources],omitempty"`
|
||||
ContainChildrenFolders bool `url:"contain[children_folders],omitempty"`
|
||||
ContainCreator bool `url:"contain[creator],omitempty"`
|
||||
ContainCreatorProfile bool `url:"contain[creator.profile],omitempty"`
|
||||
ContainModifier bool `url:"contain[modifier],omitempty"`
|
||||
ContainModiferProfile bool `url:"contain[modifier.profile],omitempty"`
|
||||
ContainPermission bool `url:"contain[permission],omitempty"`
|
||||
ContainPermissions bool `url:"contain[permissions],omitempty"`
|
||||
ContainPermissionUserProfile bool `url:"contain[permissions.user.profile],omitempty"`
|
||||
ContainPermissionGroup bool `url:"contain[permissions.group],omitempty"`
|
||||
|
||||
FilterHasID string `url:"filter[has-id][],omitempty"`
|
||||
FilterHasParent string `url:"filter[has-parent][],omitempty"`
|
||||
FilterSearch string `url:"filter[search],omitempty"`
|
||||
}
|
||||
|
||||
// GetFolders gets all Folders from the Passboltserver
|
||||
func (c *Client) GetFolders(ctx context.Context, opts *GetFolderOptions) ([]Folder, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/folders.json", "v2", nil, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var body []Folder
|
||||
err = json.Unmarshal(msg.Body, &body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// CreateFolder Creates a new Passbolt Folder
|
||||
func (c *Client) CreateFolder(ctx context.Context, folder Folder) (*Folder, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "POST", "/folders.json", "v2", folder, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(msg.Body, &folder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &folder, nil
|
||||
}
|
||||
|
||||
// GetFolder gets a Passbolt Folder
|
||||
func (c *Client) GetFolder(ctx context.Context, folderID string) (*Folder, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/folders/"+folderID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var folder Folder
|
||||
err = json.Unmarshal(msg.Body, &folder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &folder, nil
|
||||
}
|
||||
|
||||
// UpdateFolder Updates a existing Passbolt Folder
|
||||
func (c *Client) UpdateFolder(ctx context.Context, folderID string, folder Folder) (*Folder, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "PUT", "/folders/"+folderID+".json", "v2", folder, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(msg.Body, &folder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &folder, nil
|
||||
}
|
||||
|
||||
// DeleteFolder Deletes a Passbolt Folder
|
||||
func (c *Client) DeleteFolder(ctx context.Context, folderID string) error {
|
||||
_, err := c.DoCustomRequest(ctx, "DELETE", "/folders/"+folderID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MoveFolder Moves a Passbolt Folder
|
||||
func (c *Client) MoveFolder(ctx context.Context, folderID, folderParentID string) error {
|
||||
_, err := c.DoCustomRequest(ctx, "PUT", "/move/folder/"+folderID+".json", "v2", Folder{
|
||||
FolderParentID: folderParentID,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
13
go.mod
Normal file
13
go.mod
Normal file
|
@ -0,0 +1,13 @@
|
|||
module github.com/speatzle/go-passbolt
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210707164159-52430bf6b52c // indirect
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.2.2
|
||||
github.com/google/go-querystring v1.1.0
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
)
|
71
go.sum
Normal file
71
go.sum
Normal file
|
@ -0,0 +1,71 @@
|
|||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210707164159-52430bf6b52c h1:FP7mMdsXy0ybzar1sJeIcZtaJka0U/ZmLTW4wRpolYk=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210707164159-52430bf6b52c/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||
github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a h1:W6RrgN/sTxg1msqzFFb+G80MFmpjMw61IU+slm+wln4=
|
||||
github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.2.2 h1:u2m7xt+CZWj88qK1UUNBoXeJCFJwJCZ/Ff4ymGoxEXs=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.2.2/go.mod h1:ajUlBGvxMH1UBZnaYO3d1FSVzjiC6kK9XlZYGiDCvpM=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
57
gpgkey.go
Normal file
57
gpgkey.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// GPGKey is a GPGKey
|
||||
type GPGKey struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
ArmoredKey string `json:"armored_key,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
KeyCreated *Time `json:"key_created,omitempty"`
|
||||
Bits int `json:"bits,omitempty"`
|
||||
Deleted bool `json:"deleted,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
KeyID string `json:"key_id,omitempty"`
|
||||
Fingerprint string `json:"fingerprint,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Expires *Time `json:"expires,omitempty"`
|
||||
}
|
||||
|
||||
// GetGPGKeysOptions are all available query parameters
|
||||
type GetGPGKeysOptions struct {
|
||||
// This is a Unix TimeStamp
|
||||
FilterModifiedAfter int `url:"filter[modified-after],omitempty"`
|
||||
}
|
||||
|
||||
// GetGPGKeys gets all Passbolt GPGKeys
|
||||
func (c *Client) GetGPGKeys(ctx context.Context, opts *GetGPGKeysOptions) ([]GPGKey, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/gpgkeys.json", "v2", nil, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var gpgkeys []GPGKey
|
||||
err = json.Unmarshal(msg.Body, &gpgkeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gpgkeys, nil
|
||||
}
|
||||
|
||||
// GetGPGKey gets a Passbolt GPGKey
|
||||
func (c *Client) GetGPGKey(ctx context.Context, gpgkeyID string) (*GPGKey, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/gpgkeys/"+gpgkeyID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var gpgkey GPGKey
|
||||
err = json.Unmarshal(msg.Body, &gpgkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &gpgkey, nil
|
||||
}
|
97
groups.go
Normal file
97
groups.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
//Group is a Group
|
||||
type Group struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
CreatedBy string `json:"created_by,omitempty"`
|
||||
Deleted bool `json:"deleted,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
ModifiedBy string `json:"modified_by,omitempty"`
|
||||
GroupUsers []User `json:"groups_users,omitempty"`
|
||||
}
|
||||
|
||||
// GetGroupsOptions are all available query parameters
|
||||
type GetGroupsOptions struct {
|
||||
FilterHasUsers []string `url:"filter[has_users],omitempty"`
|
||||
FilterHasManagers []string `url:"filter[has-managers],omitempty"`
|
||||
|
||||
ContainModifier bool `url:"contain[modifier],omitempty"`
|
||||
ContainModifierProfile bool `url:"contain[modifier.profile],omitempty"`
|
||||
ContainUser bool `url:"contain[user],omitempty"`
|
||||
ContainGroupUser bool `url:"contain[group_user],omitempty"`
|
||||
ContainMyGroupUser bool `url:"contain[my_group_user],omitempty"`
|
||||
}
|
||||
|
||||
// GetGroups gets all Passbolt Groups
|
||||
func (c *Client) GetGroups(ctx context.Context, opts *GetGroupsOptions) ([]Group, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/groups.json", "v2", nil, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var groups []Group
|
||||
err = json.Unmarshal(msg.Body, &groups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
// CreateGroup Creates a new Passbolt Group
|
||||
func (c *Client) CreateGroup(ctx context.Context, group Group) (*Group, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "POST", "/groups.json", "v2", group, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(msg.Body, &group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &group, nil
|
||||
}
|
||||
|
||||
// GetGroup gets a Passbolt Group
|
||||
func (c *Client) GetGroup(ctx context.Context, groupID string) (*Group, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/groups/"+groupID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var group Group
|
||||
err = json.Unmarshal(msg.Body, &group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &group, nil
|
||||
}
|
||||
|
||||
// UpdateGroup Updates a existing Passbolt Group
|
||||
func (c *Client) UpdateGroup(ctx context.Context, groupID string, group Group) (*Group, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "PUT", "/groups/"+groupID+".json", "v2", group, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(msg.Body, &group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &group, nil
|
||||
}
|
||||
|
||||
// DeleteGroup Deletes a Passbolt Group
|
||||
func (c *Client) DeleteGroup(ctx context.Context, groupID string) error {
|
||||
_, err := c.DoCustomRequest(ctx, "DELETE", "/groups/"+groupID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
26
healthcheck.go
Normal file
26
healthcheck.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// PerformHealthCheck performs a Health Check
|
||||
func (c *Client) PerformHealthCheck(ctx context.Context) (json.RawMessage, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/healthcheck.json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return msg.Body, nil
|
||||
}
|
||||
|
||||
// GetHealthCheckStatus gets the Server Status
|
||||
func (c *Client) GetHealthCheckStatus(ctx context.Context) (string, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/healthcheck/status.json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(msg.Body), nil
|
||||
}
|
33
helper/folder.go
Normal file
33
helper/folder.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/speatzle/go-passbolt"
|
||||
)
|
||||
|
||||
func CreateFolder(ctx context.Context, c *passbolt.Client, folderParentID, name string) (string, error) {
|
||||
f, err := c.CreateFolder(ctx, passbolt.Folder{
|
||||
Name: name,
|
||||
FolderParentID: folderParentID,
|
||||
})
|
||||
return f.ID, err
|
||||
}
|
||||
|
||||
func GetFolder(ctx context.Context, c *passbolt.Client, folderID string) (string, string, error) {
|
||||
f, err := c.GetFolder(ctx, folderID)
|
||||
return f.FolderParentID, f.Name, err
|
||||
}
|
||||
|
||||
func UpdateFolder(ctx context.Context, c *passbolt.Client, folderID, name string) error {
|
||||
_, err := c.UpdateFolder(ctx, folderID, passbolt.Folder{Name: name})
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteFolder(ctx context.Context, c *passbolt.Client, folderID string) error {
|
||||
return c.DeleteFolder(ctx, folderID)
|
||||
}
|
||||
|
||||
func MoveFolder(ctx context.Context, c *passbolt.Client, folderID, folderParentID string) error {
|
||||
return c.MoveFolder(ctx, folderID, folderParentID)
|
||||
}
|
208
helper/resources.go
Normal file
208
helper/resources.go
Normal file
|
@ -0,0 +1,208 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/speatzle/go-passbolt"
|
||||
)
|
||||
|
||||
// CreateResource Creates a Resource where the Password and Description are Encrypted and Returns the Resources ID
|
||||
func CreateResource(ctx context.Context, c *passbolt.Client, folderParentID, name, username, uri, password, description string) (string, error) {
|
||||
types, err := c.GetResourceTypes(ctx, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Getting ResourceTypes: %w", err)
|
||||
}
|
||||
var rType *passbolt.ResourceType
|
||||
for _, tmp := range types {
|
||||
if tmp.Slug == "password-and-description" {
|
||||
rType = &tmp
|
||||
}
|
||||
}
|
||||
if rType == nil {
|
||||
return "", fmt.Errorf("Cannot find Resource type password-and-description")
|
||||
}
|
||||
|
||||
resource := passbolt.Resource{
|
||||
ResourceTypeID: rType.ID,
|
||||
FolderParentID: folderParentID,
|
||||
Name: name,
|
||||
Username: username,
|
||||
URI: uri,
|
||||
}
|
||||
|
||||
tmp := passbolt.SecretDataTypePasswordAndDescription{
|
||||
Password: password,
|
||||
Description: description,
|
||||
}
|
||||
secretData, err := json.Marshal(&tmp)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Marshalling 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 = []passbolt.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 *passbolt.Client, folderParentID, name, username, uri, password, description string) (string, error) {
|
||||
enc, err := c.EncryptMessage(password)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Encrypting Password: %w", err)
|
||||
}
|
||||
|
||||
res := passbolt.Resource{
|
||||
Name: name,
|
||||
URI: uri,
|
||||
Username: username,
|
||||
FolderParentID: folderParentID,
|
||||
Description: description,
|
||||
Secrets: []passbolt.Secret{
|
||||
{Data: enc},
|
||||
},
|
||||
}
|
||||
|
||||
resource, err := c.CreateResource(ctx, res)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Creating Resource: %w", err)
|
||||
}
|
||||
return resource.ID, nil
|
||||
}
|
||||
|
||||
// GetResource Gets a Resource by ID
|
||||
func GetResource(ctx context.Context, c *passbolt.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)
|
||||
}
|
||||
var pw string
|
||||
var desc string
|
||||
switch rType.Slug {
|
||||
case "password-string":
|
||||
pw, err = c.DecryptMessage(secret.Data)
|
||||
if err != nil {
|
||||
return "", "", "", "", "", "", fmt.Errorf("Decrypting Secret Data: %w", err)
|
||||
}
|
||||
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 passbolt.SecretDataTypePasswordAndDescription
|
||||
err = json.Unmarshal([]byte(rawSecretData), &secretData)
|
||||
if err != nil {
|
||||
return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Secret Data: %w", err)
|
||||
}
|
||||
pw = secretData.Password
|
||||
desc = secretData.Description
|
||||
default:
|
||||
return "", "", "", "", "", "", fmt.Errorf("Unknown ResourceType: %v", rType.Slug)
|
||||
}
|
||||
return resource.FolderParentID, resource.Name, resource.Username, resource.URI, pw, desc, nil
|
||||
}
|
||||
|
||||
// UpdateResource Updates all Fields.
|
||||
// Note if you want to Change the FolderParentID please use the MoveResource Function
|
||||
func UpdateResource(ctx context.Context, c *passbolt.Client, resourceID, name, username, uri, password, description string) 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)
|
||||
}
|
||||
|
||||
opts := &passbolt.GetUsersOptions{
|
||||
FilterHasAccess: resourceID,
|
||||
}
|
||||
users, err := c.GetUsers(ctx, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Getting Users: %w", err)
|
||||
}
|
||||
|
||||
newResource := passbolt.Resource{
|
||||
ID: resourceID,
|
||||
// This needs to be specified or it will revert to a legacy password
|
||||
ResourceTypeID: resource.ResourceTypeID,
|
||||
Name: name,
|
||||
Username: username,
|
||||
URI: uri,
|
||||
}
|
||||
|
||||
var secretData string
|
||||
switch rType.Slug {
|
||||
case "password-string":
|
||||
newResource.Description = description
|
||||
secretData = password
|
||||
case "password-and-description":
|
||||
tmp := passbolt.SecretDataTypePasswordAndDescription{
|
||||
Password: password,
|
||||
Description: description,
|
||||
}
|
||||
res, err := json.Marshal(&tmp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Marshalling Secret Data: %w", err)
|
||||
}
|
||||
secretData = string(res)
|
||||
default:
|
||||
return fmt.Errorf("Unknown ResourceType: %v", rType.Slug)
|
||||
}
|
||||
|
||||
newResource.Secrets = []passbolt.Secret{}
|
||||
for _, user := range users {
|
||||
var encSecretData string
|
||||
// if this is our user use our stored and verified public key instead
|
||||
if user.ID == c.GetUserID() {
|
||||
encSecretData, err = c.EncryptMessage(secretData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Encrypting Secret Data for User me: %w", err)
|
||||
}
|
||||
} else {
|
||||
encSecretData, err = c.EncryptMessageWithPublicKey(user.GPGKey.ArmoredKey, secretData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Encrypting Secret Data for User %v: %w", user.ID, err)
|
||||
}
|
||||
}
|
||||
newResource.Secrets = append(newResource.Secrets, passbolt.Secret{
|
||||
UserID: user.ID,
|
||||
Data: encSecretData,
|
||||
})
|
||||
}
|
||||
|
||||
_, err = c.UpdateResource(ctx, resourceID, newResource)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Updating Resource: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteResource(ctx context.Context, c *passbolt.Client, resourceID string) error {
|
||||
return c.DeleteResource(ctx, resourceID)
|
||||
}
|
||||
|
||||
func MoveResource(ctx context.Context, c *passbolt.Client, resourceID, folderParentID string) error {
|
||||
return c.MoveResource(ctx, resourceID, folderParentID)
|
||||
}
|
218
helper/share.go
Normal file
218
helper/share.go
Normal file
|
@ -0,0 +1,218 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/speatzle/go-passbolt"
|
||||
)
|
||||
|
||||
// ShareOperation defines how Resources are to be Shared With Users/Groups
|
||||
type ShareOperation struct {
|
||||
// Type of Permission: 1 = Read, 7 = can Update, 15 = Owner (Owner can also Share Resource)
|
||||
// Note: Setting this to -1 Will delete this Permission if it already Exists, errors if this Permission Dosen't Already Exists
|
||||
Type int
|
||||
// ARO is what Type this should be Shared With (User, Group)
|
||||
ARO string
|
||||
// AROID is the ID of the User or Group(ARO) this should be Shared With
|
||||
AROID string
|
||||
}
|
||||
|
||||
// ShareResourceWithUsersAndGroups Shares a Resource With The Users and Groups with the Specified Permission Type,
|
||||
// if the Resource has already been shared With the User/Group the Permission Type will be Adjusted/Deleted
|
||||
func ShareResourceWithUsersAndGroups(ctx context.Context, c *passbolt.Client, resourceID string, Users []string, Groups []string, permissionType int) error {
|
||||
changes := []ShareOperation{}
|
||||
for _, userID := range Users {
|
||||
changes = append(changes, ShareOperation{
|
||||
Type: permissionType,
|
||||
ARO: "User",
|
||||
AROID: userID,
|
||||
})
|
||||
}
|
||||
for _, groupID := range Groups {
|
||||
changes = append(changes, ShareOperation{
|
||||
Type: permissionType,
|
||||
ARO: "Group",
|
||||
AROID: groupID,
|
||||
})
|
||||
}
|
||||
return ShareResource(ctx, c, resourceID, changes)
|
||||
}
|
||||
|
||||
// ShareResource Shares a Resource as Specified in the Passed ShareOperation Struct Slice
|
||||
func ShareResource(ctx context.Context, c *passbolt.Client, resourceID string, changes []ShareOperation) error {
|
||||
oldPermissions, err := c.GetResourcePermissions(ctx, resourceID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Getting Resource Permissions: %w", err)
|
||||
}
|
||||
|
||||
permissionChanges, err := GeneratePermissionChanges(oldPermissions, changes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Generating Resource Permission Changes: %w", err)
|
||||
}
|
||||
|
||||
shareRequest := passbolt.ResourceShareRequest{Permissions: permissionChanges}
|
||||
|
||||
secret, err := c.GetSecret(ctx, resourceID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Get Resource: %w", err)
|
||||
}
|
||||
|
||||
secretData, err := c.DecryptMessage(secret.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Decrypting Resource Secret: %w", err)
|
||||
}
|
||||
|
||||
simulationResult, err := c.SimulateShareResource(ctx, resourceID, shareRequest)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Simulate Share Resource: %w", err)
|
||||
}
|
||||
|
||||
users, err := c.GetUsers(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Get Users: %w", err)
|
||||
}
|
||||
|
||||
shareRequest.Secrets = []passbolt.Secret{}
|
||||
for _, user := range simulationResult.Changes.Added {
|
||||
pubkey, err := getPublicKeyByUserID(user.User.ID, users)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Getting Public Key for User %v: %w", user.User.ID, err)
|
||||
}
|
||||
|
||||
encSecretData, err := c.EncryptMessageWithPublicKey(pubkey, secretData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Encrypting Secret for User %v: %w", user.User.ID, err)
|
||||
}
|
||||
shareRequest.Secrets = append(shareRequest.Secrets, passbolt.Secret{
|
||||
UserID: user.User.ID,
|
||||
Data: encSecretData,
|
||||
})
|
||||
}
|
||||
|
||||
err = c.ShareResource(ctx, resourceID, shareRequest)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Sharing Resource: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ShareFolderWithUsersAndGroups Shares a Folder With The Users and Groups with the Specified Type,
|
||||
// if the Folder has already been shared With the User/Group the Permission Type will be Adjusted/Deleted.
|
||||
// Note: Resources Permissions in the Folder are not Adjusted (Like the Extention does)
|
||||
func ShareFolderWithUsersAndGroups(ctx context.Context, c *passbolt.Client, folderID string, Users []string, Groups []string, permissionType int) error {
|
||||
changes := []ShareOperation{}
|
||||
for _, userID := range Users {
|
||||
changes = append(changes, ShareOperation{
|
||||
Type: permissionType,
|
||||
ARO: "User",
|
||||
AROID: userID,
|
||||
})
|
||||
}
|
||||
for _, groupID := range Groups {
|
||||
changes = append(changes, ShareOperation{
|
||||
Type: permissionType,
|
||||
ARO: "Group",
|
||||
AROID: groupID,
|
||||
})
|
||||
}
|
||||
return ShareFolder(ctx, c, folderID, changes)
|
||||
}
|
||||
|
||||
// ShareFolder Shares a Folder as Specified in the Passed ShareOperation Struct Slice.
|
||||
// Note Resources Permissions in the Folder are not Adjusted
|
||||
func ShareFolder(ctx context.Context, c *passbolt.Client, folderID string, changes []ShareOperation) error {
|
||||
oldPermissions, err := c.GetFolderPermissions(ctx, folderID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Getting Folder Permissions: %w", err)
|
||||
}
|
||||
|
||||
permissionChanges, err := GeneratePermissionChanges(oldPermissions, changes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Generating Folder Permission Changes: %w", err)
|
||||
}
|
||||
|
||||
err = c.ShareFolder(ctx, folderID, permissionChanges)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Sharing Folder: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GeneratePermissionChanges Generates the Permission Changes for a Resource/Folder nessesary for a single Share Operation
|
||||
func GeneratePermissionChanges(oldPermissions []passbolt.Permission, changes []ShareOperation) ([]passbolt.Permission, error) {
|
||||
// Check for Duplicate Users/Groups as that would break stuff
|
||||
for i, changeA := range changes {
|
||||
for j, changeB := range changes {
|
||||
if i != j && changeA.AROID == changeB.AROID && changeA.ARO == changeB.ARO {
|
||||
return nil, fmt.Errorf("Change %v and %v are Both About the same ARO %v ID: %v, there can only be once change per ARO", i, j, changeA.ARO, changeA.AROID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get ACO and ACO ID from Existing Permissions
|
||||
if len(oldPermissions) == 0 {
|
||||
return nil, fmt.Errorf("There has to be atleast one Permission on a ACO")
|
||||
}
|
||||
ACO := oldPermissions[0].ACO
|
||||
ACOID := oldPermissions[0].ACOForeignKey
|
||||
|
||||
permissionChanges := []passbolt.Permission{}
|
||||
for _, change := range changes {
|
||||
// Find Permission thats invloves the Same ARO as Requested in the change
|
||||
var oldPermission *passbolt.Permission
|
||||
for _, oldPerm := range oldPermissions {
|
||||
if oldPerm.ARO == change.ARO && oldPerm.AROForeignKey == change.AROID {
|
||||
oldPermission = &oldPerm
|
||||
}
|
||||
}
|
||||
// Check Wheter Matching Permission Already Exists and needs to be adjusted or is a new one can be created
|
||||
if oldPermission == nil {
|
||||
if change.Type == 15 || change.Type == 7 || change.Type == 1 {
|
||||
permissionChanges = append(permissionChanges, passbolt.Permission{
|
||||
IsNew: true,
|
||||
Type: change.Type,
|
||||
ARO: change.ARO,
|
||||
AROForeignKey: change.AROID,
|
||||
ACO: ACO,
|
||||
ACOForeignKey: ACOID,
|
||||
})
|
||||
} else if change.Type == -1 {
|
||||
return nil, fmt.Errorf("Permission for %v %v Cannot be Deleted as No Matching Permission Exists", change.ARO, change.AROID)
|
||||
} else {
|
||||
return nil, fmt.Errorf("Unknown Permission Type: %v", change.Type)
|
||||
}
|
||||
} else {
|
||||
tmp := passbolt.Permission{
|
||||
ID: oldPermission.ID,
|
||||
ARO: change.ARO,
|
||||
AROForeignKey: change.AROID,
|
||||
ACO: ACO,
|
||||
ACOForeignKey: ACOID,
|
||||
}
|
||||
|
||||
if change.Type == 15 || change.Type == 7 || change.Type == 1 {
|
||||
if oldPermission.Type == change.Type {
|
||||
return nil, fmt.Errorf("Permission for %v %v is already Type %v", change.ARO, change.AROID, change.Type)
|
||||
}
|
||||
tmp.Type = change.Type
|
||||
} else if change.Type == -1 {
|
||||
tmp.Delete = true
|
||||
tmp.Type = oldPermission.Type
|
||||
} else {
|
||||
return nil, fmt.Errorf("Unknown Permission Type: %v", change.Type)
|
||||
}
|
||||
permissionChanges = append(permissionChanges, tmp)
|
||||
}
|
||||
}
|
||||
return permissionChanges, nil
|
||||
}
|
||||
|
||||
func getPublicKeyByUserID(userID string, Users []passbolt.User) (string, error) {
|
||||
for _, user := range Users {
|
||||
if user.ID == userID {
|
||||
return user.GPGKey.ArmoredKey, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("Cannot Find Key for user id %v", userID)
|
||||
}
|
25
misc.go
Normal file
25
misc.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func randStringBytesRmndr(length int) (string, error) {
|
||||
result := ""
|
||||
for {
|
||||
if len(result) >= length {
|
||||
return result, nil
|
||||
}
|
||||
num, err := rand.Int(rand.Reader, big.NewInt(int64(127)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
n := num.Int64()
|
||||
// Make sure that the number/byte/letter is inside
|
||||
// the range of printable ASCII characters (excluding space and DEL)
|
||||
if n > 32 && n < 127 {
|
||||
result += string(n)
|
||||
}
|
||||
}
|
||||
}
|
50
permissions.go
Normal file
50
permissions.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Permission is a Permission
|
||||
type Permission struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
ACO string `json:"aco,omitempty"`
|
||||
ARO string `json:"aro,omitempty"`
|
||||
ACOForeignKey string `json:"aco_foreign_key,omitempty"`
|
||||
AROForeignKey string `json:"aro_foreign_key,omitempty"`
|
||||
Type int `json:"type,omitempty"`
|
||||
Delete bool `json:"delete,omitempty"`
|
||||
IsNew bool `json:"is_new,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
}
|
||||
|
||||
// GetResourcePermissions gets a Resources Permissions
|
||||
func (c *Client) GetResourcePermissions(ctx context.Context, resourceID string) ([]Permission, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/permissions/resource/"+resourceID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var permissions []Permission
|
||||
err = json.Unmarshal(msg.Body, &permissions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return permissions, nil
|
||||
}
|
||||
|
||||
// GetFolderPermissions gets a Folders Permissions
|
||||
func (c *Client) GetFolderPermissions(ctx context.Context, folderID string) ([]Permission, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/permissions/folder/"+folderID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var permissions []Permission
|
||||
err = json.Unmarshal(msg.Body, &permissions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return permissions, nil
|
||||
}
|
49
resource_types.go
Normal file
49
resource_types.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
//ResourceType is the Type of a Resource
|
||||
type ResourceType struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Slug string `json:"slug,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Definition json.RawMessage `json:"definition,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
}
|
||||
|
||||
type GetResourceTypesOptions struct {
|
||||
}
|
||||
|
||||
// GetResourceTypes gets all Passbolt Resource Types
|
||||
func (c *Client) GetResourceTypes(ctx context.Context, opts *GetResourceTypesOptions) ([]ResourceType, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/resource-types.json", "v2", nil, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var types []ResourceType
|
||||
err = json.Unmarshal(msg.Body, &types)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types, nil
|
||||
}
|
||||
|
||||
// GetResourceType gets a Passbolt Type
|
||||
func (c *Client) GetResourceType(ctx context.Context, typeID string) (*ResourceType, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/resource-types/"+typeID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var rType ResourceType
|
||||
err = json.Unmarshal(msg.Body, &rType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rType, nil
|
||||
}
|
135
resources.go
Normal file
135
resources.go
Normal file
|
@ -0,0 +1,135 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Resource is a Resource.
|
||||
// Warning: Since Passbolt v3 some fields here may not be populated as they may be in the Secret depending on the ResourceType,
|
||||
// for now the only Field like that is the Decription.
|
||||
type Resource struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
CreatedBy string `json:"created_by,omitempty"`
|
||||
Creator *User `json:"creator,omitempty"`
|
||||
Deleted bool `json:"deleted,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Favorite *Favorite `json:"favorite,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
ModifiedBy string `json:"modified_by,omitempty"`
|
||||
Modifier *User `json:"modifier,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Permission *Permission `json:"permission,omitempty"`
|
||||
URI string `json:"uri,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
FolderParentID string `json:"folder_parent_id,omitempty"`
|
||||
ResourceTypeID string `json:"resource_type_id,omitempty"`
|
||||
Secrets []Secret `json:"secrets,omitempty"`
|
||||
Tags []Tag `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// Tag is a Passbolt Password Tag
|
||||
type Tag struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Slug string `json:"slug,omitempty"`
|
||||
IsShared bool `json:"is_shared,omitempty"`
|
||||
}
|
||||
|
||||
// GetResourcesOptions are all available query parameters
|
||||
type GetResourcesOptions struct {
|
||||
FilterIsFavorite bool `url:"filter[is-favorite],omitempty"`
|
||||
FilterIsSharedWithMe bool `url:"filter[is-shared-with-me],omitempty"`
|
||||
FilterIsSharedWithGroup string `url:"filter[is-shared-with-group],omitempty"`
|
||||
FilterHasID string `url:"filter[has-id],omitempty"`
|
||||
// Parent Folder id
|
||||
FilterHasParent string `url:"filter[has-parent],omitempty"`
|
||||
FilterHasTag string `url:"filter[has-tag],omitempty"`
|
||||
|
||||
ContainCreator bool `url:"contain[creator],omitempty"`
|
||||
ContainFavorites bool `url:"contain[favorite],omitempty"`
|
||||
ContainModifier bool `url:"contain[modifier],omitempty"`
|
||||
ContainPermissions bool `url:"contain[permission],omitempty"`
|
||||
ContainPermissionsUserProfile bool `url:"contain[permissions.user.profile],omitempty"`
|
||||
ContainPermissionsGroup bool `url:"contain[permissions.group],omitempty"`
|
||||
ContainSecret bool `url:"contain[secret],omitempty"`
|
||||
ContainTags bool `url:"contain[tag],omitempty"`
|
||||
}
|
||||
|
||||
// GetResources gets all Passbolt Resources
|
||||
func (c *Client) GetResources(ctx context.Context, opts *GetResourcesOptions) ([]Resource, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/resources.json", "v2", nil, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resources []Resource
|
||||
err = json.Unmarshal(msg.Body, &resources)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
// CreateResource Creates a new Passbolt Resource
|
||||
func (c *Client) CreateResource(ctx context.Context, resource Resource) (*Resource, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "POST", "/resources.json", "v2", resource, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(msg.Body, &resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resource, nil
|
||||
}
|
||||
|
||||
// GetResource gets a Passbolt Resource
|
||||
func (c *Client) GetResource(ctx context.Context, resourceID string) (*Resource, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/resources/"+resourceID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resource Resource
|
||||
err = json.Unmarshal(msg.Body, &resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resource, nil
|
||||
}
|
||||
|
||||
// UpdateResource Updates a existing Passbolt Resource
|
||||
func (c *Client) UpdateResource(ctx context.Context, resourceID string, resource Resource) (*Resource, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "PUT", "/resources/"+resourceID+".json", "v2", resource, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(msg.Body, &resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resource, nil
|
||||
}
|
||||
|
||||
// DeleteResource Deletes a Passbolt Resource
|
||||
func (c *Client) DeleteResource(ctx context.Context, resourceID string) error {
|
||||
_, err := c.DoCustomRequest(ctx, "DELETE", "/resources/"+resourceID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MoveResource Moves a Passbolt Resource
|
||||
func (c *Client) MoveResource(ctx context.Context, resourceID, folderParentID string) error {
|
||||
_, err := c.DoCustomRequest(ctx, "PUT", "/move/resource/"+resourceID+".json", "v2", Resource{
|
||||
FolderParentID: folderParentID,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
55
roles.go
Normal file
55
roles.go
Normal file
|
@ -0,0 +1,55 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
//Role is a Role
|
||||
type Role struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
Avatar Avatar `json:"avatar,omitempty"`
|
||||
}
|
||||
|
||||
// Avatar is a Users Avatar
|
||||
type Avatar struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
UserID string `json:"user_id,omitempty"`
|
||||
ForeignKey string `json:"foreign_key,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
Filename string `json:"filename,omitempty"`
|
||||
Filesize int `json:"filesize,omitempty"`
|
||||
MimeType string `json:"mime_type,omitempty"`
|
||||
Extension string `json:"extension,omitempty"`
|
||||
Hash string `json:"hash,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Adapter string `json:"adapter,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
URL *URL `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// URL is a Passbolt URL
|
||||
type URL struct {
|
||||
Medium string `json:"medium,omitempty"`
|
||||
Small string `json:"small,omitempty"`
|
||||
}
|
||||
|
||||
// GetRoles gets all Passbolt Roles
|
||||
func (c *Client) GetRoles(ctx context.Context) ([]Role, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/roles.json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var roles []Role
|
||||
err = json.Unmarshal(msg.Body, &roles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return roles, nil
|
||||
}
|
36
secrets.go
Normal file
36
secrets.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Secret is a Secret
|
||||
type Secret struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
UserID string `json:"user_id,omitempty"`
|
||||
ResourceID string `json:"resource_id,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
}
|
||||
|
||||
type SecretDataTypePasswordAndDescription struct {
|
||||
Password string `json:"password"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// GetSecret gets a Passbolt Secret
|
||||
func (c *Client) GetSecret(ctx context.Context, resourceID string) (*Secret, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/secrets/resource/"+resourceID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var secret Secret
|
||||
err = json.Unmarshal(msg.Body, &secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &secret, nil
|
||||
}
|
93
share.go
Normal file
93
share.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// ResourceShareRequest is a ResourceShareRequest
|
||||
type ResourceShareRequest struct {
|
||||
Permissions []Permission `json:"permissions,omitempty"`
|
||||
Secrets []Secret `json:"secrets,omitempty"`
|
||||
}
|
||||
|
||||
// ResourceShareSimulationResult is the Result of a Sharing Siumulation
|
||||
type ResourceShareSimulationResult struct {
|
||||
Changes ResourceShareSimulationChanges `json:"changes,omitempty"`
|
||||
}
|
||||
|
||||
type ResourceShareSimulationChanges struct {
|
||||
Added []ResourceShareSimulationChange `json:"added,omitempty"`
|
||||
Removed []ResourceShareSimulationChange `json:"removed,omitempty"`
|
||||
}
|
||||
|
||||
type ResourceShareSimulationChange struct {
|
||||
User ResourceShareSimulationUser `json:"user,omitempty"`
|
||||
}
|
||||
|
||||
type ResourceShareSimulationUser struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
// ARO is a User or a Group
|
||||
type ARO struct {
|
||||
User
|
||||
Group
|
||||
}
|
||||
|
||||
// SearchAROsOptions are all available query parameters
|
||||
type SearchAROsOptions struct {
|
||||
FilterSearch string `url:"filter[search],omitempty"`
|
||||
}
|
||||
|
||||
// SearchAROs gets all Passbolt AROs
|
||||
func (c *Client) SearchAROs(ctx context.Context, opts SearchAROsOptions) ([]ARO, error) {
|
||||
//set is_new to true in permission
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/share/search-aros.json", "v2", nil, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var aros []ARO
|
||||
err = json.Unmarshal(msg.Body, &aros)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return aros, nil
|
||||
}
|
||||
|
||||
// ShareResource Shares a Resource with AROs
|
||||
func (c *Client) ShareResource(ctx context.Context, resourceID string, shareRequest ResourceShareRequest) error {
|
||||
_, err := c.DoCustomRequest(ctx, "PUT", "/share/resource/"+resourceID+".json", "v2", shareRequest, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ShareFolder Shares a Folder with AROs
|
||||
func (c *Client) ShareFolder(ctx context.Context, folderID string, permissions []Permission) error {
|
||||
f := Folder{Permissions: permissions}
|
||||
_, err := c.DoCustomRequest(ctx, "PUT", "/share/folder/"+folderID+".json", "v2", f, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SimulateShareResource Simulates Shareing a Resource with AROs
|
||||
func (c *Client) SimulateShareResource(ctx context.Context, resourceID string, shareRequest ResourceShareRequest) (*ResourceShareSimulationResult, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "POST", "/share/simulate/resource/"+resourceID+".json", "v2", shareRequest, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res ResourceShareSimulationResult
|
||||
err = json.Unmarshal(msg.Body, &res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
}
|
10
staticcheck.conf
Normal file
10
staticcheck.conf
Normal file
|
@ -0,0 +1,10 @@
|
|||
checks = ["all", "-ST1005", "-ST1000", "-ST1003", "-ST1016"]
|
||||
initialisms = ["ACL", "API", "ASCII", "CPU", "CSS", "DNS",
|
||||
"EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID",
|
||||
"IP", "JSON", "QPS", "RAM", "RPC", "SLA",
|
||||
"SMTP", "SQL", "SSH", "TCP", "TLS", "TTL",
|
||||
"UDP", "UI", "GID", "UID", "UUID", "URI",
|
||||
"URL", "UTF8", "VM", "XML", "XMPP", "XSRF",
|
||||
"XSS"]
|
||||
dot_import_whitelist = []
|
||||
http_status_code_whitelist = ["200", "400", "404", "500"]
|
29
time.go
Normal file
29
time.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Time is here to unmarshall time correctly
|
||||
type Time struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
// UnmarshalJSON Parses Passbolt *Time
|
||||
func (t *Time) UnmarshalJSON(buf []byte) error {
|
||||
if string(buf) == "null" {
|
||||
return nil
|
||||
}
|
||||
tt, err := time.Parse(time.RFC3339, strings.Trim(string(buf), `"`))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Time = tt
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON Marshals Passbolt *Time
|
||||
func (t Time) MarshalJSON() ([]byte, error) {
|
||||
return []byte(`"` + t.Time.Format(time.RFC3339) + `"`), nil
|
||||
}
|
124
users.go
Normal file
124
users.go
Normal file
|
@ -0,0 +1,124 @@
|
|||
package passbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// User contains information about a passbolt User
|
||||
type User struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
Active bool `json:"active,omitempty"`
|
||||
Deleted bool `json:"deleted,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Favorite *Favorite `json:"favorite,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
RoleID string `json:"role_id,omitempty"`
|
||||
Profile *Profile `json:"profile,omitempty"`
|
||||
Role *Role `json:"role,omitempty"`
|
||||
GPGKey *GPGKey `json:"gpgKey,omitempty"`
|
||||
LastLoggedIn string `json:"last_logged_in,omitempty"`
|
||||
}
|
||||
|
||||
// Profile is a Profile
|
||||
type Profile struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
UserID string `json:"user_id,omitempty"`
|
||||
FirstName string `json:"first_name,omitempty"`
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
Created *Time `json:"created,omitempty"`
|
||||
Modified *Time `json:"modified,omitempty"`
|
||||
}
|
||||
|
||||
// GetUsersOptions are all available query parameters
|
||||
type GetUsersOptions struct {
|
||||
FilterSearch string `url:"filter[search],omitempty"`
|
||||
FilterHasGroup string `url:"filter[has-group],omitempty"`
|
||||
FilterHasAccess string `url:"filter[has-access],omitempty"`
|
||||
FilterIsAdmin bool `url:"filter[is-admin],omitempty"`
|
||||
|
||||
ContainLastLoggedIn bool `url:"contain[LastLoggedIn],omitempty"`
|
||||
}
|
||||
|
||||
// GetUsers gets all Passbolt Users
|
||||
func (c *Client) GetUsers(ctx context.Context, opts *GetUsersOptions) ([]User, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/users.json", "v2", nil, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var users []User
|
||||
err = json.Unmarshal(msg.Body, &users)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
|
||||
// CreateUser Creates a new Passbolt User
|
||||
func (c *Client) CreateUser(ctx context.Context, user User) (*User, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "POST", "/users.json", "v2", user, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(msg.Body, &user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// GetMe gets the currently logged in Passbolt User
|
||||
func (c *Client) GetMe(ctx context.Context) (*User, error) {
|
||||
return c.GetUser(ctx, "me")
|
||||
}
|
||||
|
||||
// GetUser gets a Passbolt User
|
||||
func (c *Client) GetUser(ctx context.Context, userID string) (*User, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "GET", "/users/"+userID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var user User
|
||||
err = json.Unmarshal(msg.Body, &user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// UpdateUser Updates a existing Passbolt User
|
||||
func (c *Client) UpdateUser(ctx context.Context, userID string, user User) (*User, error) {
|
||||
msg, err := c.DoCustomRequest(ctx, "PUT", "/users/"+userID+".json", "v2", user, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(msg.Body, &user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// DeleteUser Deletes a Passbolt User
|
||||
func (c *Client) DeleteUser(ctx context.Context, userID string) error {
|
||||
_, err := c.DoCustomRequest(ctx, "DELETE", "/users/"+userID+".json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteUserDryrun Check if a Passbolt User is Deleteable
|
||||
func (c *Client) DeleteUserDryrun(ctx context.Context, userID string) error {
|
||||
_, err := c.DoCustomRequest(ctx, "DELETE", "/users/"+userID+"/dry-run.json", "v2", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Add table
Reference in a new issue