A Go Module to interact with Passbolt, a Open source Password Manager for Teams

go-passbolt

Go Reference

A Go Module to interact with Passbolt, a Open source Password Manager for Teams

This Module tries to Support the Latest Passbolt Community/PRO Server Release, PRO Features Such as Folders are Supported. Older Versions of Passbolt such as v2 are unsupported (it's a Password Manager, please update it)

This Module is split into 2 packages: api and helper, in the api package you will find everything to directly interact with the API. The helper Package has simplified functions that use the api package to perform common but complicated tasks such as Sharing a Password. To use the API Package please read the Passbolt API Docs. Sadly the Docs aren't Complete so many Things here have been found by looking at the source of Passbolt or through trial and error, if you have a Question just ask.

PR's are Welcome, if it's something bigger / fundamental: Please make a Issue and ask first.

Install

go get github.com/speatzle/go-passbolt

Examples

Login

First you will need to Create a Client, and then Login on the Server using the Client

package main

import (
	"context"
	"fmt"

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

const address = "https://passbolt.example.com"
const userPassword = "aStrongPassword"
const userPrivateKey = `
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: OpenPGP.js v4.6.2
Comment: https://openpgpjs.org
klasd...
-----END PGP PRIVATE KEY BLOCK-----`

func main() {
	client, err := api.NewClient(nil, "", address, userPrivateKey, userPassword)
	if err != nil {
		panic(err)
	}

    	ctx := context.TODO()

	err = client.Login(ctx)
	if err != nil {
		panic(err)
	}
	fmt.Println("Logged in!")
}

Note: if you want to use the client for some time then you'll have to make sure it is still logged in. You can do this using the client.CheckSession() function.

Create a Resource

Creating a Resource using the helper package is simple, first add "github.com/speatzle/go-passbolt/helper" to your imports. Then you can simply:

resourceID, err := helper.CreateResource(
	ctx,                        // Context
	client,                     // API Client
	"",                         // ID of Parent Folder (PRO only)
	"Example Account",          // Name
	"user123",                  // Username
	"https://test.example.com", // URI
	"securePassword123",        // Password
	"This is a Account for the example test portal", // Description
)

Creating a (Legacy) Resource Without the helper package would look like this:

enc, err := client.EncryptMessage("securePassword123")
if err != nil {
	panic(err)
}

res := api.Resource{
	Name:           "Example Account",
	Username:       "user123",
	URI:            "https://test.example.com",
	Description:    "This is a Account for the example test portal",
	Secrets: []api.Secret{
		{Data: enc},
	},
}

resource, err := client.CreateResource(ctx, res)
if err != nil {
	panic(err)
}

Note: Since Passbolt v3 There are Resource Types, this Manual Example just creates a "password-string" Type Password where the Description is Unencrypted, Read More Here.

Getting

Generally API Get Calls will have options (opts) that allow for specifing filters and contains, if you dont want to specify options just pass nil. Filters just filter by whatever is given, contains on the otherhand specify what to include in the response. Many Filters And Contains are undocumented in the Passbolt Docs.

Here We Specify that we want to Filter by Favorites and that the Response Should Contain the Permissions for each Resource:

favorites, err := client.GetResources(ctx, &api.GetResourcesOptions{
	FilterIsFavorite: true,
    	ContainPermissions: true,
})

We Can do the Same for Users:

users, err := client.GetUsers(ctx, &api.GetUsersOptions{
	FilterSearch:        "Samuel",
	ContainLastLoggedIn: true,
})

Groups:

groups, err := client.GetGroups(ctx, &api.GetGroupsOptions{
    	FilterHasUsers: []string{"id of user", "id of other user"},
	ContainUser: true,
})

And also for Folders (PRO Only):

folders, err := client.GetFolders(ctx, &api.GetFolderOptions{
	FilterSearch:             "Test Folder",
	ContainChildrenResources: true,
})

Getting by ID is also Supported Using the Singular Form:

resource, err := client.GetResource(ctx, "resource ID")

Since the Password is Encrypted (and sometimes the description too) the helper package has a function to decrypt all encrypted fields Automatically:

folderParentID, name, username, uri, password, description, err := helper.GetResource(ctx, client, "resource id")

Updating

The Helper Package has a function to save you needing to deal with Resource Types When Updating a Resource:

err := helper.UpdateResource(ctx, client,"resource id", "name", "username", "https://test.example.com", "pass123", "very descriptive")

Note: As Groups are also Complicated to Update there will be a helper function for them in the future.

For other less Complicated Updates you can Simply use the Client directly:

client.UpdateUser(ctx, "user id", api.User{
	Profile: &api.Profile{
		FirstName: "Test",
		LastName:  "User",
	},
})

Sharing

As Sharing Resources is very Complicated there are multipe helper Functions. During Sharing you will encounter the permissionType.

The permissionType can be 1 for Read only, 7 for Can Update, 15 for Owner or -1 if you want to delete Existing Permissions.

The ShareResourceWithUsersAndGroups function Shares the Resource With all Provided Users and Groups with the Given permissionType.

err := helper.ShareResourceWithUsersAndGroups(ctx, client, "resource id", []string{"user 1 id"}, []string{"group 1 id"}, 7)

Note: Existing Permission of Users and Groups will be adjusted to be of the Provided permissionType.

If you need to do something more Complicated like setting Users/Groups to different Type then you can Use ShareResource directly:

changes := []helper.ShareOperation{}

// Make this User Owner
changes = append(changes, ShareOperation{
	Type:  15,
	ARO:   "User",
	AROID: "user 1 id",
})

// Make this User Can Update
changes = append(changes, ShareOperation{
	Type:  5,
	ARO:   "User",
	AROID: "user 2 id",
})

// Delete This Users Current Permission
changes = append(changes, ShareOperation{
	Type:  -1,
	ARO:   "User",
	AROID: "user 3 id",
})

// Make this Group Read Only
changes = append(changes, ShareOperation{
	Type:  1,
	ARO:   "Group",
	AROID: "group 1 id",
})

err := helper.ShareResource(ctx, c, resourceID, changes)

Note: These Functions are Also Availabe for Folders (PRO)

Moveing (PRO)

In Passbolt PRO there are Folders, during Creation of Resources and Folders you can Specify in which Folder you want to create the Resource / Folder inside of. But if you want to change which Folder the Resource / Folder is in then you can't use the Update function (it is / was possible to update the parent Folder using the Update function but that breaks things). Instead you use the Move function.

err := client.MoveResource(ctx, "resource id", "parent folder id")
err := client.MoveFolder(ctx, "folder id", "parent folder id")

Other

These Examples are just the main Usecases of this Modules, there are many more API calls that are supported. Look at the Reference for more information.

Full Example

This Example Creates a Resource, Searches for a User Named Test User, Checks that its Not itself and Shares the Password with the Test User if Nessesary:

package main

import (
	"context"
	"fmt"

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

const address = "https://passbolt.example.com"
const userPassword = "aStrongPassword"
const userPrivateKey = `
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: OpenPGP.js v4.6.2
Comment: https://openpgpjs.org
klasd...
-----END PGP PRIVATE KEY BLOCK-----`

func main() {
	ctx := context.TODO()

	client, err := api.NewClient(nil, "", address, userPrivateKey, userPassword)
	if err != nil {
		panic(err)
	}

	err = client.Login(ctx)
	if err != nil {
		panic(err)
	}
	fmt.Println("Logged in!")

	resourceID, err := helper.CreateResource(
		ctx,                        // Context
		client,                     // API Client
		"",                         // ID of Parent Folder (PRO only)
		"Example Account",          // Name
		"user123",                  // Username
		"https://test.example.com", // URI
		"securePassword123",        // Password
		"This is a Account for the example test portal", // Description
	)
	if err != nil {
		panic(err)
	}

	fmt.Println("Created Resource")

	users, err := client.GetUsers(ctx, &api.GetUsersOptions{
		FilterSearch: "Test User",
	})
	if err != nil {
		panic(err)
	}

	if len(users) == 0 {
		panic("Cannot Find Test User")
	}

	if client.GetUserID() == users[0].ID {
		fmt.Println("I am the Test User, No Need to Share Password With myself")
        client.Logout(ctx)
		return
	}

	helper.ShareResourceWithUsersAndGroups(ctx, client, resourceID, []string{users[0].ID}, []string{}, 7)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Shared Resource With Test User %v\n", users[0].ID)

    	client.Logout(ctx)
}

TODO

  • get a Passbolt Instance to Work in Github Actions
  • write Integration Tests
  • add ability to verify Server
  • add helper functions for updating Groups
Similar Resources

Open Source Web Application Firewall

Open Source Web Application Firewall

DEPRECATED This repository started as a good idea but I didn't have enough time or desire to work on it. So, it's left here for historical / education

Nov 24, 2022

SingularityCE is the Community Edition of Singularity, an open source container platform designed to be simple, fast, and secure.

SingularityCE Guidelines for Contributing Pull Request Template Project License Documentation Support Citation SingularityCE is the Community Edition

Jan 5, 2023

CrowdSec - an open-source massively multiplayer firewall able to analyze visitor behavior & provide an adapted response to all kinds of attacks. It also leverages the crowd power to generate a global IP reputation database to protect the user network.

CrowdSec - an open-source massively multiplayer firewall able to analyze visitor behavior & provide an adapted response to all kinds of attacks. It also leverages the crowd power to generate a global IP reputation database to protect the user network.

📚 Documentation 💠 Configuration Hub 💬 Discourse (Forum) 💬 Gitter (Live chat) 💃 This is a community driven project, we need your feedback. TL;DR

Jan 5, 2023

BluePhish: Open-Source Phishing Toolkit (Direct Fork of GoPhish)

BluePhish: Open-Source Phishing Toolkit (Direct Fork of GoPhish)

BluePhish BluePhish: Open-Source Phishing Toolkit (Direct Fork of GoPhish) Gophish is an open-source phishing toolkit designed for businesses and pene

Jun 1, 2022

Gitrob: Putting the Open Source in OSINT

 Gitrob: Putting the Open Source in OSINT

Gitrob: Putting the Open Source in OSINT Gitrob is a tool to help find potentially sensitive files pushed to public repositories on Github. Gitrob wil

Dec 28, 2022

An open source platform for inter-operable smart contracts which automatically execute

An open source platform for inter-operable smart contracts which automatically execute

CHT ❗️ For issue disclosure, check out SECURITY.md ❗️ Juno is an open source platform for inter-operable smart contracts which automatically execute,

Sep 21, 2022

A light package for generating and comparing password hashing with argon2 in Go

argon2-hashing argon2-hashing provides a light wrapper around Go's argon2 package. Argon2 was the winner of the Password Hashing Competition that make

Sep 27, 2022

Argon2 password hashing package for go with constant time hash comparison

argon2pw Argon2 password hashing package with constant time hash comparison Preface: Argon2 was selected as the winner of the Password Hashing Competi

Sep 27, 2022

Password generator written in Go

go-generate-password Password generator written in Go. Use as a library or as a CLI. Usage CLI go-generate-password can be used on the cli, just insta

Dec 19, 2022
Comments
  • Issue while fetching resources-data with filter

    Issue while fetching resources-data with filter

    Hello there, i'm currently playing around with the Passbolt-API and this beautiful written go module.

    While playing around, an error occured while fetching resources filtered by groups. See: FilterIsSharedWithGroup

    Request:

    groupuuids := make([]string, 0)
    
    for _, element := range Groups {
    	groupuuids = append(groupuuids, element.GroupUUID)
    }
    
    res, err := client.GetResources(ctx, &pbapi.GetResourcesOptions{
    	FilterIsSharedWithGroup: []string{groupuuids[1]},
    })
    if err != nil {
    	log.Fatal(err)
    	panic(err)
    }
    fmt.Println(res)
    

    Log: 2022/04/12 16:14:29 Error API JSON Response Status: Message: An Internal Error Has Occurred., Body: ""

    Server-Error-Log: 2022-04-12 14:25:02 Error: [TypeError] Argument 1 passed to App\Controller\Component\QueryStringComponent::validateFilterGroup() must be of the type string, bool given, called in /usr/share/php/passbolt/src/Controller/Component/QueryStringComponent.php on line 299 in /usr/share/php/passbolt/src/Controller/Component/QueryStringComponent.php on line 543 Request URL: /resources.json?api-version=v2&filter%5Bis-shared-with-group%5D%5B%5D=641d3d65-3ce6-4e6d-ba94-034bbd86f04b Client IP: xx.xx.xxx.xxx

    In result, the same issue occures with usage of go-cli.

    Looks like there is some sort of TypeError even thoo i provided the required type (Array of group-uuids as string). I tried to locate the issue with another filter, which runs through exactly the same filter-validator, but in another request: That worked perfectly.

    I took a quick look at the validators. Turns out is-shared-with-group is executes validateFilterGroup which only takes one string/group-uuid as value.

    Switch-Case:

                    case 'has-groups':
                        self::validateFilterGroups($values, $filterName);
                        break;
                    case 'has-parent':
                        self::validateFilterParentFolders($values, $filterName);
                        break;
                    case 'is-shared-with-group':
                        self::validateFilterGroup($values, $filterName);
                        break;
    

    The validator function:

    public static function validateFilterGroup(string $groupId, string $filterName): bool
    {
        if (!Validation::uuid($groupId)) {
            throw new Exception(__('"{0}" is not a valid group id for filter {1}.', $groupId, $filterName));
        }
    
        return true;
    }
    

    I tried to use validateFilterGroups (like in has-groups) instead of validateFilterGroup to work with an array. That threw me the same error (but i'm far away from a php-expert lol).

    To continue working on my project, i modified the GetResourcesOptions-type to let FilterIsSharedWithGroup use a single string instead of an array:

    // GetResourcesOptions are all available query parameters
    type GetResourcesOptions struct {
    	FilterIsFavorite                   bool     `url:"filter[is-favorite],omitempty"`
    	FilterIsSharedWithGroup   string   `url:"filter[is-shared-with-group],omitempty"
    

    That worked pretty well for me but it's restricting me to filter through multiple groups at once.

    All my packages are up-to-date. The server is running on a debian environment.

    Does anyone know if this is an known issue?

    Would be nice if somebody could fix this (:

    Have a good one, marvsman

CLI client (and Golang module) for deps.dev API. Free access to dependencies, licenses, advisories, and other critical health and security signals for open source package versions.
CLI client (and Golang module) for deps.dev API. Free access to dependencies, licenses, advisories, and other critical health and security signals for open source package versions.

depsdev CLI client (and Golang module) for deps.dev API. Free access to dependencies, licenses, advisories, and other critical health and security sig

May 11, 2023
Not Yet Another Password Manager written in Go using libsodium

secrets Secure and simple passwords manager written in Go. It aims to be NYAPM (Not Yet Another Password Manager), but tries to be different from othe

May 30, 2022
password manager using age for encryption

page ====== password manager using age (https://age-encryption.org/) for encryption. encrypted secrets are files in the $PAGE_SECRETS/ directory that

May 30, 2022
Password manager written in golang
Password manager written in golang

Go password manager Password manager written in golang. Dependencies: gpg golang

Dec 2, 2021
Simple password manager app in GO

Introduction This is my first project in Go, a password manager application. A humble attempt at execution of an idea I've had for some time now. The

Sep 13, 2022
go-opa-validate is an open-source lib that evaluates OPA (open policy agent) policy against JSON or YAML data.
go-opa-validate is an open-source lib that evaluates OPA (open policy agent) policy against JSON or YAML data.

go-opa-validate go-opa-validate is an open-source lib that evaluates OPA (open policy agent) policy against JSON or YAML data. Installation Usage Cont

Nov 17, 2022
mesh-kridik is an open-source security scanner that performs various security checks on a Kubernetes cluster with istio service mesh and is leveraged by OPA (Open Policy Agent) to enforce security rules.
mesh-kridik is an open-source security scanner that performs various security checks on a Kubernetes cluster with istio service mesh and is leveraged by OPA (Open Policy Agent) to enforce security rules.

mesh-kridik Enhance your Kubernetes service mesh security !! mesh-kridik is an open-source security scanner that performs various security checks on a

Dec 14, 2022
PHP functions implementation to Golang. This package is for the Go beginners who have developed PHP code before. You can use PHP like functions in your app, module etc. when you add this module to your project.

PHP Functions for Golang - phpfuncs PHP functions implementation to Golang. This package is for the Go beginners who have developed PHP code before. Y

Dec 30, 2022
EarlyBird is a sensitive data detection tool capable of scanning source code repositories for clear text password violations, PII, outdated cryptography methods, key files and more.
EarlyBird is a sensitive data detection tool capable of scanning source code repositories for clear text password violations, PII, outdated cryptography methods, key files and more.

EarlyBird is a sensitive data detection tool capable of scanning source code repositories for clear text password violations, PII, outdated cryptograp

Dec 10, 2022
DockerSlim (docker-slim): Don't change anything in your Docker container image and minify it by up to 30x (and for compiled languages even more) making it secure too! (free and open source)
DockerSlim (docker-slim): Don't change anything in your Docker container image and minify it by up to 30x (and for compiled languages even more) making it secure too! (free and open source)

Minify and Secure Docker containers (free and open source!) Don't change anything in your Docker container image and minify it by up to 30x making it

Dec 27, 2022