mirror of
https://github.com/passbolt/go-passbolt.git
synced 2025-05-13 19:18:20 +00:00
Compare commits
36 commits
Author | SHA1 | Date | |
---|---|---|---|
b919c3e09d | |||
3762c5e278 | |||
26942f22d1 | |||
![]() |
c1904ca20a | ||
ddaa090bc7 | |||
c86afac97c | |||
2b3bb48385 | |||
83ba14250b | |||
390b7be866 | |||
aaf7213315 | |||
1bbe7dc952 | |||
1499a80625 | |||
e13f484bcb | |||
360cc3748e | |||
a6a98a6887 | |||
8dbb07720d | |||
605db2b047 | |||
adaffbce7e | |||
7316263056 | |||
876631e7c2 | |||
a9bd51e5da | |||
ce38d65e45 | |||
e4537a8ca0 | |||
![]() |
1b178b6634 | ||
![]() |
a86ae886f2 | ||
![]() |
fd895a9d46 | ||
![]() |
ced16f2479 | ||
![]() |
1aaafcf66e | ||
![]() |
8a5cbff839 | ||
![]() |
5ce26cfbfc | ||
![]() |
4d482e6bf2 | ||
![]() |
563c755168 | ||
![]() |
9e181e6c83 | ||
![]() |
df43c781ad | ||
![]() |
1b30521b5b | ||
![]() |
69221b3a24 |
23 changed files with 344 additions and 113 deletions
8
.github/workflows/.go.yml
vendored
8
.github/workflows/.go.yml
vendored
|
@ -13,17 +13,17 @@ jobs:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.17
|
go-version: 1.23
|
||||||
- name: "Setup Passbolt"
|
- name: "Setup Passbolt"
|
||||||
run: |
|
run: |
|
||||||
git clone https://github.com/passbolt/passbolt_docker.git ../passbolt_docker
|
git clone https://github.com/passbolt/passbolt_docker.git ../passbolt_docker
|
||||||
cd ../passbolt_docker
|
cd ../passbolt_docker
|
||||||
docker-compose -f docker-compose/docker-compose-ce.yaml up -d
|
docker compose -f docker-compose/docker-compose-ce.yaml up -d
|
||||||
docker ps -a
|
docker ps -a
|
||||||
- name: "Test"
|
- name: "Test"
|
||||||
run: |
|
run: |
|
||||||
docker exec docker-compose_passbolt_1 sh -c '/usr/bin/wait-for.sh -t 30 localhost:443'
|
docker exec docker-compose-passbolt-1 sh -c '/usr/bin/wait-for.sh -t 30 localhost:443'
|
||||||
output=$(docker exec docker-compose_passbolt_1 sh -c 'su -m -c "/usr/share/php/passbolt/bin/cake \
|
output=$(docker exec docker-compose-passbolt-1 sh -c 'su -m -c "/usr/share/php/passbolt/bin/cake \
|
||||||
passbolt register_user \
|
passbolt register_user \
|
||||||
-u your@email.com \
|
-u your@email.com \
|
||||||
-f yourname \
|
-f yourname \
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2021 speatzle
|
Copyright (c) 2021 Samuel Lorch
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
28
README.md
28
README.md
|
@ -1,9 +1,10 @@
|
||||||
# go-passbolt
|
# go-passbolt
|
||||||
[](https://pkg.go.dev/github.com/speatzle/go-passbolt)
|
|
||||||
|
[](https://pkg.go.dev/github.com/passbolt/go-passbolt)
|
||||||
|
|
||||||
A Go module to interact with [Passbolt](https://www.passbolt.com/), an open-source password manager for teams
|
A Go module to interact with [Passbolt](https://www.passbolt.com/), an open-source password manager for teams
|
||||||
|
|
||||||
There also is a CLI Tool to interact with Passbolt using this module [here](https://github.com/speatzle/go-passbolt-cli).
|
There also is a CLI Tool to interact with Passbolt using this module [here](https://github.com/passbolt/go-passbolt-cli).
|
||||||
|
|
||||||
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 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)
|
||||||
|
|
||||||
|
@ -15,16 +16,16 @@ The helper package has simplified functions that use the API package to perform
|
||||||
|
|
||||||
To use the API package, please read the [Passbolt API docs](https://help.passbolt.com/api). 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.
|
To use the API package, please read the [Passbolt API docs](https://help.passbolt.com/api). 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. But be gentle: if it's something bigger or fundamental: please [create an issue](https://github.com/speatzle/go-passbolt/issues/new) and ask first.
|
PR's are welcome. But be gentle: if it's something bigger or fundamental: please [create an issue](https://github.com/passbolt/go-passbolt/issues/new) and ask first.
|
||||||
|
|
||||||
Disclaimer: This project is community driven and not associated with Passbolt SA
|
Disclaimer: This project is community driven and not associated with Passbolt SA
|
||||||
|
|
||||||
|
|
||||||
# Install
|
# Install
|
||||||
|
|
||||||
`go get github.com/speatzle/go-passbolt`
|
`go get github.com/passbolt/go-passbolt`
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
## Login
|
## Login
|
||||||
|
|
||||||
First, you will need to create a client and then log in on the server using the client:
|
First, you will need to create a client and then log in on the server using the client:
|
||||||
|
@ -36,7 +37,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/speatzle/go-passbolt/api"
|
"github.com/passbolt/go-passbolt/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
const address = "https://passbolt.example.com"
|
const address = "https://passbolt.example.com"
|
||||||
|
@ -70,7 +71,7 @@ You can do this using the `client.CheckSession()` function.
|
||||||
|
|
||||||
## Create a Resource
|
## Create a Resource
|
||||||
|
|
||||||
Creating a resource using the helper package is simple. First, add `"github.com/speatzle/go-passbolt/helper"` to your imports.
|
Creating a resource using the helper package is simple. First, add `"github.com/passbolt/go-passbolt/helper"` to your imports.
|
||||||
|
|
||||||
Then you can simply:
|
Then you can simply:
|
||||||
|
|
||||||
|
@ -214,6 +215,7 @@ err = helper.UpdateUser(
|
||||||
"lastname", // LastName
|
"lastname", // LastName
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: These helpers will only update fields that are not "".
|
Note: These helpers will only update fields that are not "".
|
||||||
|
|
||||||
Helper update functions also exists for Folders.
|
Helper update functions also exists for Folders.
|
||||||
|
@ -227,7 +229,7 @@ During sharing you will encounter the [permission type](https://github.com/passb
|
||||||
The `permissionType` can be:
|
The `permissionType` can be:
|
||||||
|
|
||||||
| Code | Meaning |
|
| Code | Meaning |
|
||||||
| --- | --- |
|
| ---- | -------------------------- |
|
||||||
| `1` | "Read-only" |
|
| `1` | "Read-only" |
|
||||||
| `7` | "Can update" |
|
| `7` | "Can update" |
|
||||||
| `15` | "Owner" |
|
| `15` | "Owner" |
|
||||||
|
@ -294,6 +296,7 @@ err := client.MoveFolder(ctx, "folder id", "parent folder id")
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
You can setup a Account using a Invite Link like this:
|
You can setup a Account using a Invite Link like this:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Get the UserID and Token from the Invite Link
|
// Get the UserID and Token from the Invite Link
|
||||||
userID, token, err := ParseInviteUrl(url)
|
userID, token, err := ParseInviteUrl(url)
|
||||||
|
@ -327,12 +330,11 @@ if err != nil {
|
||||||
|
|
||||||
## MFA
|
## MFA
|
||||||
|
|
||||||
go-passbolt now supports MFA! You can set it up using the Client's `MFACallback` function, it will provide everything you need to complete any MFA challanges. When your done you just need to return the new MFA Cookie (usually called passbolt_mfa). The helper package has a example implementation for a noninteractive TOTP Setup under helper/mfa.go in the function `AddMFACallbackTOTP`.
|
go-passbolt now supports MFA! You can set it up using the Client's `MFACallback` function, it will provide everything you need to complete any MFA challenges. When your done you just need to return the new MFA Cookie (usually called passbolt_mfa). The helper package has a example implementation for a noninteractive TOTP Setup under helper/mfa.go in the function `AddMFACallbackTOTP`.
|
||||||
|
|
||||||
## Other
|
## Other
|
||||||
|
|
||||||
These examples are just the main use cases of these Modules, many more API calls are supported. Look at the [reference](https://pkg.go.dev/github.com/speatzle/go-passbolt) for more information.
|
These examples are just the main use cases of these Modules, many more API calls are supported. Look at the [reference](https://pkg.go.dev/github.com/passbolt/go-passbolt) for more information.
|
||||||
|
|
||||||
|
|
||||||
## Full Example
|
## Full Example
|
||||||
|
|
||||||
|
@ -350,8 +352,8 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/speatzle/go-passbolt/api"
|
"github.com/passbolt/go-passbolt/api"
|
||||||
"github.com/speatzle/go-passbolt/helper"
|
"github.com/passbolt/go-passbolt/helper"
|
||||||
)
|
)
|
||||||
|
|
||||||
const address = "https://passbolt.example.com"
|
const address = "https://passbolt.example.com"
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// APIResponse is the Struct representation of a Json Response
|
// APIResponse is the Struct representation of a Json Response
|
||||||
|
@ -62,9 +63,9 @@ start:
|
||||||
if res.Header.Status == "success" {
|
if res.Header.Status == "success" {
|
||||||
return r, &res, nil
|
return r, &res, nil
|
||||||
} else if res.Header.Status == "error" {
|
} else if res.Header.Status == "error" {
|
||||||
if res.Header.Code == 403 && res.Header.Message == "MFA authentication is required." {
|
if res.Header.Code == 403 && strings.HasSuffix(res.Header.URL, "/mfa/verify/error.json") {
|
||||||
if !firstTime {
|
if !firstTime {
|
||||||
// if we are here this probably means that the MFA callback is broken, to prevent a infinit loop lets error here
|
// if we are here this probably means that the MFA callback is broken, to prevent a infinite loop lets error here
|
||||||
return r, &res, fmt.Errorf("Got MFA challenge twice in a row, is your MFA Callback broken? Bailing to prevent loop...:")
|
return r, &res, fmt.Errorf("Got MFA challenge twice in a row, is your MFA Callback broken? Bailing to prevent loop...:")
|
||||||
}
|
}
|
||||||
if c.MFACallback != nil {
|
if c.MFACallback != nil {
|
||||||
|
@ -72,11 +73,11 @@ start:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r, &res, fmt.Errorf("MFA Callback: %w", err)
|
return r, &res, fmt.Errorf("MFA Callback: %w", err)
|
||||||
}
|
}
|
||||||
// ok, we got the MFA challange and the callback presumably handeld it so we can retry the original request
|
// ok, we got the MFA challenge and the callback presumably handled it so we can retry the original request
|
||||||
firstTime = false
|
firstTime = false
|
||||||
goto start
|
goto start
|
||||||
} else {
|
} else {
|
||||||
return r, &res, fmt.Errorf("Got MFA Challange but the MFA callback is not defined")
|
return r, &res, fmt.Errorf("Got MFA Challenge but the MFA callback is not defined")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r, &res, fmt.Errorf("%w: Message: %v, Body: %v", ErrAPIResponseErrorStatusCode, res.Header.Message, string(res.Body))
|
return r, &res, fmt.Errorf("%w: Message: %v, Body: %v", ErrAPIResponseErrorStatusCode, res.Header.Message, string(res.Body))
|
||||||
|
|
|
@ -31,7 +31,7 @@ type Client struct {
|
||||||
userPublicKey string
|
userPublicKey string
|
||||||
userID string
|
userID string
|
||||||
|
|
||||||
// used for solving MFA challanges. You can block this to for example wait for user input.
|
// used for solving MFA challenges. You can block this to for example wait for user input.
|
||||||
// You shouden't run any unrelated API Calls while you are in this callback.
|
// You shouden't run any unrelated API Calls while you are in this callback.
|
||||||
// You need to Return the Cookie that Passbolt expects to verify you MFA, usually it is called passbolt_mfa
|
// You need to Return the Cookie that Passbolt expects to verify you MFA, usually it is called passbolt_mfa
|
||||||
MFACallback func(ctx context.Context, c *Client, res *APIResponse) (http.Cookie, error)
|
MFACallback func(ctx context.Context, c *Client, res *APIResponse) (http.Cookie, error)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
type MFAChallange struct {
|
type MFAChallenge struct {
|
||||||
Provider MFAProviders `json:"providers,omitempty"`
|
Provider MFAProviders `json:"providers,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,6 @@ type MFAProviders struct {
|
||||||
TOTP string `json:"totp,omitempty"`
|
TOTP string `json:"totp,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MFAChallangeResponse struct {
|
type MFAChallengeResponse struct {
|
||||||
TOTP string `json:"totp,omitempty"`
|
TOTP string `json:"totp,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,11 @@ type ResourceType struct {
|
||||||
Modified *Time `json:"modified,omitempty"`
|
Modified *Time `json:"modified,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ResourceTypeSchema struct {
|
||||||
|
Resource json.RawMessage `json:"resource"`
|
||||||
|
Secret json.RawMessage `json:"secret"`
|
||||||
|
}
|
||||||
|
|
||||||
// GetResourceTypesOptions is a placeholder for future options
|
// GetResourceTypesOptions is a placeholder for future options
|
||||||
type GetResourceTypesOptions struct {
|
type GetResourceTypesOptions struct {
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ type Tag struct {
|
||||||
// GetResourcesOptions are all available query parameters
|
// GetResourcesOptions are all available query parameters
|
||||||
type GetResourcesOptions struct {
|
type GetResourcesOptions struct {
|
||||||
FilterIsFavorite bool `url:"filter[is-favorite],omitempty"`
|
FilterIsFavorite bool `url:"filter[is-favorite],omitempty"`
|
||||||
FilterIsSharedWithGroup []string `url:"filter[is-shared-with-group][],omitempty"`
|
FilterIsSharedWithGroup string `url:"filter[is-shared-with-group],omitempty"`
|
||||||
FilterIsOwnedByMe bool `url:"filter[is-owned-by-me],omitempty"`
|
FilterIsOwnedByMe bool `url:"filter[is-owned-by-me],omitempty"`
|
||||||
FilterIsSharedWithMe bool `url:"filter[is-shared-with-me],omitempty"`
|
FilterIsSharedWithMe bool `url:"filter[is-shared-with-me],omitempty"`
|
||||||
FilterHasID []string `url:"filter[has-id][],omitempty"`
|
FilterHasID []string `url:"filter[has-id][],omitempty"`
|
||||||
|
|
|
@ -22,6 +22,25 @@ type SecretDataTypePasswordAndDescription struct {
|
||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SecretDataTOTP struct {
|
||||||
|
Algorithm string `json:"algorithm"`
|
||||||
|
SecretKey string `json:"secret_key"`
|
||||||
|
Digits int `json:"digits"`
|
||||||
|
Period int `json:"period"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretDataTypeTOTP is the format a secret of resource type "totp" is stored in
|
||||||
|
type SecretDataTypeTOTP struct {
|
||||||
|
TOTP SecretDataTOTP `json:"totp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretDataTypePasswordDescriptionTOTP is the format a secret of resource type "password-description-totp" is stored in
|
||||||
|
type SecretDataTypePasswordDescriptionTOTP struct {
|
||||||
|
Password string `json:"password"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
TOTP SecretDataTOTP `json:"totp"`
|
||||||
|
}
|
||||||
|
|
||||||
// GetSecret gets a Passbolt Secret
|
// GetSecret gets a Passbolt Secret
|
||||||
func (c *Client) GetSecret(ctx context.Context, resourceID string) (*Secret, error) {
|
func (c *Client) GetSecret(ctx context.Context, resourceID string) (*Secret, error) {
|
||||||
err := checkUUIDFormat(resourceID)
|
err := checkUUIDFormat(resourceID)
|
||||||
|
|
|
@ -33,7 +33,7 @@ func (c *Client) SetupServerVerification(ctx context.Context) (string, string, e
|
||||||
token := "gpgauthv1.3.0|36|" + uuid.String() + "|gpgauthv1.3.0"
|
token := "gpgauthv1.3.0|36|" + uuid.String() + "|gpgauthv1.3.0"
|
||||||
encToken, err := c.EncryptMessageWithPublicKey(serverKey, token)
|
encToken, err := c.EncryptMessageWithPublicKey(serverKey, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", fmt.Errorf("Encrypting Challange: %w", err)
|
return "", "", fmt.Errorf("Encrypting Challenge: %w", err)
|
||||||
}
|
}
|
||||||
err = c.VerifyServer(ctx, token, encToken)
|
err = c.VerifyServer(ctx, token, encToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -57,7 +57,7 @@ func (c *Client) VerifyServer(ctx context.Context, token, encToken string) error
|
||||||
}
|
}
|
||||||
raw, _, err := c.DoCustomRequestAndReturnRawResponse(ctx, "POST", "/auth/verify.json", "v2", data, nil)
|
raw, _, err := c.DoCustomRequestAndReturnRawResponse(ctx, "POST", "/auth/verify.json", "v2", data, nil)
|
||||||
if err != nil && !strings.Contains(err.Error(), "The authentication failed.") {
|
if err != nil && !strings.Contains(err.Error(), "The authentication failed.") {
|
||||||
return fmt.Errorf("Sending Verification Challange: %w", err)
|
return fmt.Errorf("Sending Verification Challenge: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if raw.Header.Get("X-GPGAuth-Verify-Response") != token {
|
if raw.Header.Get("X-GPGAuth-Verify-Response") != token {
|
||||||
|
|
23
go.mod
23
go.mod
|
@ -1,13 +1,20 @@
|
||||||
module github.com/speatzle/go-passbolt
|
module github.com/passbolt/go-passbolt
|
||||||
|
|
||||||
go 1.16
|
go 1.23.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.4.2
|
github.com/ProtonMail/gopenpgp/v2 v2.8.3
|
||||||
github.com/google/go-querystring v1.1.0
|
github.com/google/go-querystring v1.1.0
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
github.com/santhosh-tekuri/jsonschema v1.2.4
|
||||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 // indirect
|
)
|
||||||
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a // indirect
|
|
||||||
golang.org/x/text v0.3.7 // indirect
|
require (
|
||||||
|
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||||
|
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect
|
||||||
|
github.com/cloudflare/circl v1.6.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
golang.org/x/crypto v0.35.0 // indirect
|
||||||
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
|
golang.org/x/text v0.22.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
112
go.sum
112
go.sum
|
@ -1,10 +1,21 @@
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f h1:J2FzIrXN82q5uyUraeJpLIm7U6PffRwje2ORho5yIik=
|
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||||
github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a h1:W6RrgN/sTxg1msqzFFb+G80MFmpjMw61IU+slm+wln4=
|
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||||
github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4=
|
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.4.2 h1:xPcQYAa3D3V2sDhJq0bYWwlWtxzTudxm1/XXHlSWcJo=
|
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.4.2/go.mod h1:0byYFEOo6x4F/1YqhN7Z6m015Cqnxllz3CGb5cjJueY=
|
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
|
||||||
|
github.com/ProtonMail/gopenpgp/v2 v2.7.5 h1:STOY3vgES59gNgoOt2w0nyHBjKViB/qSg7NjbQWPJkA=
|
||||||
|
github.com/ProtonMail/gopenpgp/v2 v2.7.5/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g=
|
||||||
|
github.com/ProtonMail/gopenpgp/v2 v2.8.3 h1:1jHlELwCR00qovx2B50DkL/FjYwt/P91RnlsqeOp2Hs=
|
||||||
|
github.com/ProtonMail/gopenpgp/v2 v2.8.3/go.mod h1:LiuOTbnJit8w9ZzOoLscj0kmdALY7hfoCVh5Qlb0bcg=
|
||||||
|
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||||
|
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||||
|
github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE=
|
||||||
|
github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||||
|
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
|
||||||
|
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
@ -12,64 +23,71 @@ 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-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 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
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 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis=
|
||||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4=
|
||||||
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.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.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
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-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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE=
|
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
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-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/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/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-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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a h1:ppl5mZgokTT8uPkmYOyEUmPTr3ypaKkg5eFOGrAmxxE=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||||
|
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/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/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||||
|
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
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-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/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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=
|
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/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.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/speatzle/go-passbolt/api"
|
"github.com/passbolt/go-passbolt/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateFolder Creates a new Folder
|
// CreateFolder Creates a new Folder
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/speatzle/go-passbolt/api"
|
"github.com/passbolt/go-passbolt/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GroupMembershipOperation creates/modifies/deletes a group membership
|
// GroupMembershipOperation creates/modifies/deletes a group membership
|
||||||
|
@ -14,7 +14,7 @@ type GroupMembershipOperation struct {
|
||||||
Delete bool
|
Delete bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// GroupMembership containes who and what kind of membership they have with a group
|
// GroupMembership contains who and what kind of membership they have with a group
|
||||||
type GroupMembership struct {
|
type GroupMembership struct {
|
||||||
UserID string
|
UserID string
|
||||||
Username string
|
Username string
|
||||||
|
|
|
@ -8,18 +8,18 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/speatzle/go-passbolt/api"
|
"github.com/passbolt/go-passbolt/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddMFACallbackTOTP adds a MFA callback to the client that generates OTP Codes on demand using a Token with configurable retries and delay
|
// AddMFACallbackTOTP adds a MFA callback to the client that generates OTP Codes on demand using a Token with configurable retries and delay
|
||||||
func AddMFACallbackTOTP(c *api.Client, retrys uint, retryDelay, offset time.Duration, token string) {
|
func AddMFACallbackTOTP(c *api.Client, retrys uint, retryDelay, offset time.Duration, token string) {
|
||||||
c.MFACallback = func(ctx context.Context, c *api.Client, res *api.APIResponse) (http.Cookie, error) {
|
c.MFACallback = func(ctx context.Context, c *api.Client, res *api.APIResponse) (http.Cookie, error) {
|
||||||
challange := api.MFAChallange{}
|
challenge := api.MFAChallenge{}
|
||||||
err := json.Unmarshal(res.Body, &challange)
|
err := json.Unmarshal(res.Body, &challenge)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.Cookie{}, fmt.Errorf("Parsing MFA Challange")
|
return http.Cookie{}, fmt.Errorf("Parsing MFA Challenge")
|
||||||
}
|
}
|
||||||
if challange.Provider.TOTP == "" {
|
if challenge.Provider.TOTP == "" {
|
||||||
return http.Cookie{}, fmt.Errorf("Server Provided no TOTP Provider")
|
return http.Cookie{}, fmt.Errorf("Server Provided no TOTP Provider")
|
||||||
}
|
}
|
||||||
for i := uint(0); i < retrys+1; i++ {
|
for i := uint(0); i < retrys+1; i++ {
|
||||||
|
@ -28,14 +28,14 @@ func AddMFACallbackTOTP(c *api.Client, retrys uint, retryDelay, offset time.Dura
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.Cookie{}, fmt.Errorf("Error Generating MFA Code: %w", err)
|
return http.Cookie{}, fmt.Errorf("Error Generating MFA Code: %w", err)
|
||||||
}
|
}
|
||||||
req := api.MFAChallangeResponse{
|
req := api.MFAChallengeResponse{
|
||||||
TOTP: code,
|
TOTP: code,
|
||||||
}
|
}
|
||||||
var raw *http.Response
|
var raw *http.Response
|
||||||
raw, _, err = c.DoCustomRequestAndReturnRawResponse(ctx, "POST", "mfa/verify/totp.json", "v2", req, nil)
|
raw, _, err = c.DoCustomRequestAndReturnRawResponse(ctx, "POST", "mfa/verify/totp.json", "v2", req, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Unwrap(err) != api.ErrAPIResponseErrorStatusCode {
|
if errors.Unwrap(err) != api.ErrAPIResponseErrorStatusCode {
|
||||||
return http.Cookie{}, fmt.Errorf("Doing MFA Challange Response: %w", err)
|
return http.Cookie{}, fmt.Errorf("Doing MFA Challenge Response: %w", err)
|
||||||
}
|
}
|
||||||
// MFA failed, so lets wait just let the loop try again
|
// MFA failed, so lets wait just let the loop try again
|
||||||
time.Sleep(retryDelay)
|
time.Sleep(retryDelay)
|
||||||
|
@ -49,6 +49,6 @@ func AddMFACallbackTOTP(c *api.Client, retrys uint, retryDelay, offset time.Dura
|
||||||
return http.Cookie{}, fmt.Errorf("Unable to find Passbolt MFA Cookie")
|
return http.Cookie{}, fmt.Errorf("Unable to find Passbolt MFA Cookie")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return http.Cookie{}, fmt.Errorf("Failed MFA Challange 3 times: %w", err)
|
return http.Cookie{}, fmt.Errorf("Failed MFA Challenge 3 times: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/speatzle/go-passbolt/api"
|
"github.com/passbolt/go-passbolt/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateResource Creates a Resource where the Password and Description are Encrypted and Returns the Resources ID
|
// CreateResource Creates a Resource where the Password and Description are Encrypted and Returns the Resources ID
|
||||||
|
@ -18,6 +18,7 @@ func CreateResource(ctx context.Context, c *api.Client, folderParentID, name, us
|
||||||
for _, tmp := range types {
|
for _, tmp := range types {
|
||||||
if tmp.Slug == "password-and-description" {
|
if tmp.Slug == "password-and-description" {
|
||||||
rType = &tmp
|
rType = &tmp
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rType == nil {
|
if rType == nil {
|
||||||
|
@ -41,6 +42,11 @@ func CreateResource(ctx context.Context, c *api.Client, folderParentID, name, us
|
||||||
return "", fmt.Errorf("Marshalling Secret Data: %w", err)
|
return "", fmt.Errorf("Marshalling Secret Data: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = validateSecretData(rType, string(secretData))
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Validating Secret Data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
encSecretData, err := c.EncryptMessage(string(secretData))
|
encSecretData, err := c.EncryptMessage(string(secretData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Encrypting Secret Data for User me: %w", err)
|
return "", fmt.Errorf("Encrypting Secret Data for User me: %w", err)
|
||||||
|
@ -122,6 +128,21 @@ func GetResourceFromData(c *api.Client, resource api.Resource, secret api.Secret
|
||||||
}
|
}
|
||||||
pw = secretData.Password
|
pw = secretData.Password
|
||||||
desc = secretData.Description
|
desc = secretData.Description
|
||||||
|
case "password-description-totp":
|
||||||
|
rawSecretData, err := c.DecryptMessage(secret.Data)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", "", "", "", fmt.Errorf("Decrypting Secret Data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var secretData api.SecretDataTypePasswordDescriptionTOTP
|
||||||
|
err = json.Unmarshal([]byte(rawSecretData), &secretData)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Secret Data: %w", err)
|
||||||
|
}
|
||||||
|
pw = secretData.Password
|
||||||
|
desc = secretData.Description
|
||||||
|
case "totp":
|
||||||
|
// nothing fits into the interface in this case
|
||||||
default:
|
default:
|
||||||
return "", "", "", "", "", "", fmt.Errorf("Unknown ResourceType: %v", rType.Slug)
|
return "", "", "", "", "", "", fmt.Errorf("Unknown ResourceType: %v", rType.Slug)
|
||||||
}
|
}
|
||||||
|
@ -218,10 +239,62 @@ func UpdateResource(ctx context.Context, c *api.Client, resourceID, name, userna
|
||||||
return fmt.Errorf("Marshalling Secret Data: %w", err)
|
return fmt.Errorf("Marshalling Secret Data: %w", err)
|
||||||
}
|
}
|
||||||
secretData = string(res)
|
secretData = string(res)
|
||||||
|
case "password-description-totp":
|
||||||
|
secret, err := c.GetSecret(ctx, resourceID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Getting Secret: %w", err)
|
||||||
|
}
|
||||||
|
oldSecretData, err := c.DecryptMessage(secret.Data)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Decrypting Secret: %w", err)
|
||||||
|
}
|
||||||
|
var oldSecret api.SecretDataTypePasswordDescriptionTOTP
|
||||||
|
err = json.Unmarshal([]byte(oldSecretData), &secretData)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Parsing Decrypted Secret Data: %w", err)
|
||||||
|
}
|
||||||
|
if password != "" {
|
||||||
|
oldSecret.Password = password
|
||||||
|
}
|
||||||
|
if description != "" {
|
||||||
|
oldSecret.Description = description
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := json.Marshal(&oldSecret)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Marshalling Secret Data: %w", err)
|
||||||
|
}
|
||||||
|
secretData = string(res)
|
||||||
|
case "totp":
|
||||||
|
secret, err := c.GetSecret(ctx, resourceID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Getting Secret: %w", err)
|
||||||
|
}
|
||||||
|
oldSecretData, err := c.DecryptMessage(secret.Data)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Decrypting Secret: %w", err)
|
||||||
|
}
|
||||||
|
var oldSecret api.SecretDataTypeTOTP
|
||||||
|
err = json.Unmarshal([]byte(oldSecretData), &secretData)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Parsing Decrypted Secret Data: %w", err)
|
||||||
|
}
|
||||||
|
// since we don't have totp parameters we don't do anything
|
||||||
|
|
||||||
|
res, err := json.Marshal(&oldSecret)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Marshalling Secret Data: %w", err)
|
||||||
|
}
|
||||||
|
secretData = string(res)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Unknown ResourceType: %v", rType.Slug)
|
return fmt.Errorf("Unknown ResourceType: %v", rType.Slug)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = validateSecretData(rType, secretData)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Validating Secret Data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
newResource.Secrets = []api.Secret{}
|
newResource.Secrets = []api.Secret{}
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
var encSecretData string
|
var encSecretData string
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/speatzle/go-passbolt/api"
|
"github.com/passbolt/go-passbolt/api"
|
||||||
|
|
||||||
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
||||||
"github.com/ProtonMail/gopenpgp/v2/helper"
|
"github.com/ProtonMail/gopenpgp/v2/helper"
|
||||||
|
@ -31,7 +31,7 @@ func SetupAccount(ctx context.Context, c *api.Client, userID, token, password st
|
||||||
|
|
||||||
keyName := install.Profile.FirstName + " " + install.Profile.LastName + " " + install.Username
|
keyName := install.Profile.FirstName + " " + install.Profile.LastName + " " + install.Username
|
||||||
|
|
||||||
privateKey, err := helper.GenerateKey(keyName, install.Username, []byte(password), "rsa", 2048)
|
privateKey, err := helper.GenerateKey(keyName, install.Username, []byte(password), "rsa", 4096)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Generating Private Key: %w", err)
|
return "", fmt.Errorf("Generating Private Key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/speatzle/go-passbolt/api"
|
"github.com/passbolt/go-passbolt/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
var client *api.Client
|
var client *api.Client
|
||||||
|
@ -31,6 +31,9 @@ func TestMain(m *testing.M) {
|
||||||
panic(fmt.Errorf("Creating Registration Client: %w", err))
|
panic(fmt.Errorf("Creating Registration Client: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug Output
|
||||||
|
rc.Debug = true
|
||||||
|
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
|
|
||||||
privkey, err := SetupAccount(ctx, rc, userID, token, "password123")
|
privkey, err := SetupAccount(ctx, rc, userID, token, "password123")
|
||||||
|
@ -43,6 +46,9 @@ func TestMain(m *testing.M) {
|
||||||
panic(fmt.Errorf("Setup Client: %w", err))
|
panic(fmt.Errorf("Setup Client: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug Output
|
||||||
|
c.Debug = true
|
||||||
|
|
||||||
c.Login(ctx)
|
c.Login(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("Login Client: %w", err))
|
panic(fmt.Errorf("Login Client: %w", err))
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/speatzle/go-passbolt/api"
|
"github.com/passbolt/go-passbolt/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ShareOperation defines how Resources are to be Shared With Users/Groups
|
// ShareOperation defines how Resources are to be Shared With Users/Groups
|
||||||
|
@ -63,6 +63,22 @@ func ShareResource(ctx context.Context, c *api.Client, resourceID string, change
|
||||||
return fmt.Errorf("Decrypting Resource Secret: %w", err)
|
return fmt.Errorf("Decrypting Resource Secret: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Secret Validation
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = validateSecretData(rType, secretData)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Validating Secret Data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
simulationResult, err := c.SimulateShareResource(ctx, resourceID, shareRequest)
|
simulationResult, err := c.SimulateShareResource(ctx, resourceID, shareRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Simulate Share Resource: %w", err)
|
return fmt.Errorf("Simulate Share Resource: %w", err)
|
||||||
|
|
|
@ -33,6 +33,9 @@ func GenerateOTPCode(token string, when time.Time) (string, error) {
|
||||||
// It should be uppercase always
|
// It should be uppercase always
|
||||||
token = strings.ToUpper(token)
|
token = strings.ToUpper(token)
|
||||||
|
|
||||||
|
// Remove all the extra "=" padding at the end
|
||||||
|
token = strings.TrimRight(token, "=")
|
||||||
|
|
||||||
secretBytes, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(token)
|
secretBytes, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Decoding token string: %w", err)
|
return "", fmt.Errorf("Decoding token string: %w", err)
|
||||||
|
|
36
helper/totp_test.go
Normal file
36
helper/totp_test.go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testCases = []struct {
|
||||||
|
description string
|
||||||
|
token string
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{"generates otpcode from token with padding", "PGWXXL7B66MMSRBAWSKEKIYD3P675KRJ===", false},
|
||||||
|
{"generates otpcode from token without padding", "JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP", false},
|
||||||
|
{"invalid token format", "INVALIDTOKEN123", true},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateOTPCode(t *testing.T) {
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
code, err := GenerateOTPCode(tc.token, time.Now())
|
||||||
|
|
||||||
|
if tc.expectErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected error for input '%s', but got none", tc.token)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("GenerateOTPCode returned an error: %s", err.Error())
|
||||||
|
} else if len(code) != 6 {
|
||||||
|
t.Errorf("Expected 6-digit OTP, got: %s", code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/speatzle/go-passbolt/api"
|
"github.com/passbolt/go-passbolt/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateUser Creates a new User
|
// CreateUser Creates a new User
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
package helper
|
package helper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/speatzle/go-passbolt/api"
|
"github.com/passbolt/go-passbolt/api"
|
||||||
|
"github.com/santhosh-tekuri/jsonschema"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getPublicKeyByUserID(userID string, Users []api.User) (string, error) {
|
func getPublicKeyByUserID(userID string, Users []api.User) (string, error) {
|
||||||
|
@ -32,3 +36,44 @@ func getSecretByResourceID(secrets []api.Secret, resourceID string) (*api.Secret
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("Cannot Find Secret for id %v", resourceID)
|
return nil, fmt.Errorf("Cannot Find Secret for id %v", resourceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateSecretData(rType *api.ResourceType, secretData string) error {
|
||||||
|
var schemaDefinition api.ResourceTypeSchema
|
||||||
|
err := json.Unmarshal([]byte(rType.Definition), &schemaDefinition)
|
||||||
|
if err != nil {
|
||||||
|
// Workaround for inconsistant API Responses where sometime the Schema is embedded directly and sometimes it's escaped as a string
|
||||||
|
if err.Error() == "json: cannot unmarshal string into Go value of type api.ResourceTypeSchema" {
|
||||||
|
var tmp string
|
||||||
|
err = json.Unmarshal([]byte(rType.Definition), &tmp)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Workaround Unmarshal Json Schema String: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(tmp), &schemaDefinition)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Workaround Unmarshal Json Schema: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("Unmarshal Json Schema: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
comp := jsonschema.NewCompiler()
|
||||||
|
|
||||||
|
err = comp.AddResource("secret.json", bytes.NewReader(schemaDefinition.Secret))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Adding Json Schema: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
schema, err := comp.Compile("secret.json")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Compiling Json Schema: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = schema.Validate(strings.NewReader(secretData))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Validating Secret Data: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue