Add text format for signets and envelopes and support for import/export
This commit is contained in:
parent
74d41194cc
commit
d4d06574b8
15 changed files with 393 additions and 10 deletions
|
@ -30,7 +30,7 @@ func newEnvelope(name string) (*jess.Envelope, error) {
|
||||||
"Encrypt with key",
|
"Encrypt with key",
|
||||||
"Encrypt for someone and sign",
|
"Encrypt for someone and sign",
|
||||||
"Encrypt for someone but don't sign",
|
"Encrypt for someone but don't sign",
|
||||||
"Sign a file",
|
"Sign a file (wrapped)",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := survey.AskOne(prompt, &preset, nil)
|
err := survey.AskOne(prompt, &preset, nil)
|
||||||
|
@ -93,6 +93,7 @@ func editEnvelope(envelope *jess.Envelope) error {
|
||||||
{"Recipients", formatSignetNames(envelope.Recipients)},
|
{"Recipients", formatSignetNames(envelope.Recipients)},
|
||||||
{"Senders", formatSignetNames(envelope.Senders)},
|
{"Senders", formatSignetNames(envelope.Senders)},
|
||||||
{""},
|
{""},
|
||||||
|
{"Export", "export to text format"},
|
||||||
{"Abort", "discard changes and return"},
|
{"Abort", "discard changes and return"},
|
||||||
{"Delete", "delete and return"},
|
{"Delete", "delete and return"},
|
||||||
}),
|
}),
|
||||||
|
@ -105,21 +106,28 @@ func editEnvelope(envelope *jess.Envelope) error {
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(submenu, "Done"):
|
case strings.HasPrefix(submenu, "Done"):
|
||||||
// Check if the envolope is valid.
|
// Check if the envelope is valid.
|
||||||
if envelope.SecurityLevel == 0 {
|
if envelope.SecurityLevel == 0 {
|
||||||
fmt.Println("Envelope is invalid, please fix before saving.")
|
fmt.Println("Envelope is invalid, please fix before saving.")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Remove and keys and save.
|
// Remove and keys and save.
|
||||||
_ = envelope.LoopSecrets("", func(signet *jess.Signet) error {
|
envelope.CleanSignets()
|
||||||
signet.Key = nil
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
_ = envelope.LoopSenders("", func(signet *jess.Signet) error {
|
|
||||||
signet.Key = nil
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return trustStore.StoreEnvelope(envelope)
|
return trustStore.StoreEnvelope(envelope)
|
||||||
|
case strings.HasPrefix(submenu, "Export"):
|
||||||
|
// Check if the envelope is valid.
|
||||||
|
if envelope.SecurityLevel == 0 {
|
||||||
|
fmt.Println("Envelope is invalid, please fix before exporting.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Remove keys and export.
|
||||||
|
envelope.CleanSignets()
|
||||||
|
text, err := envelope.Export(false)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to export: %w", err)
|
||||||
|
}
|
||||||
|
fmt.Println("Exported envelope:")
|
||||||
|
fmt.Println(text)
|
||||||
case strings.HasPrefix(submenu, "Abort"):
|
case strings.HasPrefix(submenu, "Abort"):
|
||||||
return nil
|
return nil
|
||||||
case strings.HasPrefix(submenu, "Delete"):
|
case strings.HasPrefix(submenu, "Delete"):
|
||||||
|
|
14
cmd/testdata/.truststore/3911c84c-78f7-4354-a7f5-0e115aa2903c.recipient
vendored
Normal file
14
cmd/testdata/.truststore/3911c84c-78f7-4354-a7f5-0e115aa2903c.recipient
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
J{
|
||||||
|
"Version": 1,
|
||||||
|
"ID": "3911c84c-78f7-4354-a7f5-0e115aa2903c",
|
||||||
|
"Scheme": "Ed25519",
|
||||||
|
"Key": "ATYVZjmhR1Zwe0KAPV99pzbzI+6zWgKvELNhFwolRdnv",
|
||||||
|
"Public": true,
|
||||||
|
"Info": {
|
||||||
|
"Name": "Safing Code Signing Cert 1",
|
||||||
|
"Owner": "",
|
||||||
|
"Created": "2022-07-11T10:23:31.705715613+02:00",
|
||||||
|
"Expires": "0001-01-01T00:00:00Z",
|
||||||
|
"Details": null
|
||||||
|
}
|
||||||
|
}
|
13
cmd/testdata/.truststore/3911c84c-78f7-4354-a7f5-0e115aa2903c.signet
vendored
Normal file
13
cmd/testdata/.truststore/3911c84c-78f7-4354-a7f5-0e115aa2903c.signet
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
J{
|
||||||
|
"Version": 1,
|
||||||
|
"ID": "3911c84c-78f7-4354-a7f5-0e115aa2903c",
|
||||||
|
"Scheme": "Ed25519",
|
||||||
|
"Key": "Aee5n/V1wJM8aNpaNEPBEPeN6S0Tl41OJP0rHwtsGcZcNhVmOaFHVnB7QoA9X32nNvMj7rNaAq8Qs2EXCiVF2e8=",
|
||||||
|
"Info": {
|
||||||
|
"Name": "Safing Code Signing Cert 1",
|
||||||
|
"Owner": "",
|
||||||
|
"Created": "2022-07-11T10:23:31.705715613+02:00",
|
||||||
|
"Expires": "0001-01-01T00:00:00Z",
|
||||||
|
"Details": null
|
||||||
|
}
|
||||||
|
}
|
23
cmd/testdata/.truststore/safing-codesign-1.envelope
vendored
Normal file
23
cmd/testdata/.truststore/safing-codesign-1.envelope
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
J{
|
||||||
|
"Version": 1,
|
||||||
|
"Name": "safing-codesign-1",
|
||||||
|
"SuiteID": "signfile_v1",
|
||||||
|
"Secrets": null,
|
||||||
|
"Senders": [
|
||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"ID": "3911c84c-78f7-4354-a7f5-0e115aa2903c",
|
||||||
|
"Scheme": "Ed25519",
|
||||||
|
"Key": null,
|
||||||
|
"Info": {
|
||||||
|
"Name": "Safing Code Signing Cert 1",
|
||||||
|
"Owner": "",
|
||||||
|
"Created": "2022-07-11T10:23:31.705715613+02:00",
|
||||||
|
"Expires": "0001-01-01T00:00:00Z",
|
||||||
|
"Details": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Recipients": null,
|
||||||
|
"SecurityLevel": 128
|
||||||
|
}
|
1
cmd/testdata/test.txt
vendored
Normal file
1
cmd/testdata/test.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hello world!
|
13
cmd/testdata/test.txt.letter
vendored
Normal file
13
cmd/testdata/test.txt.letter
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
‘J{
|
||||||
|
"Version": 1,
|
||||||
|
"SuiteID": "signfile_v1",
|
||||||
|
"Nonce": "pKOQBQ==",
|
||||||
|
"Signatures": [
|
||||||
|
{
|
||||||
|
"Scheme": "Ed25519",
|
||||||
|
"ID": "3911c84c-78f7-4354-a7f5-0e115aa2903c",
|
||||||
|
"Value": "ftsIINZ9oApKiXYQTcLIdAZDSflp6nRN/y8Gm0rdQC+3/wal6Q+7N3N8HEAxpoxWseSQNaRVCT9hSnRQStHYBA=="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
hello world!
|
9
cmd/testdata/test.txt.sig
vendored
Normal file
9
cmd/testdata/test.txt.sig
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
-----BEGIN JESS SIGNATURE-----
|
||||||
|
Q6VnVmVyc2lvbgFnU3VpdGVJRGtzaWduZmlsZV92MWVOb25jZUQb+MqAZERhdGFY
|
||||||
|
d02Dq0xhYmVsZWRIYXNoxCIJIOz3Afcn2eLXfEqkmsb7vMmXJ4rKAQvd7rlhwQz1
|
||||||
|
TUNaqFNpZ25lZEF01v9iy+uLqE1ldGFEYXRhgqd2ZXJzaW9upTAuMC4xqmlkZW50
|
||||||
|
aWZpZXKyd2luZG93cy9jb2RlL3RoaW5nalNpZ25hdHVyZXOBo2ZTY2hlbWVnRWQy
|
||||||
|
NTUxOWJJRHgkMzkxMWM4NGMtNzhmNy00MzU0LWE3ZjUtMGUxMTVhYTI5MDNjZVZh
|
||||||
|
bHVlWECJZFbIifczUGAJkmATXCHy/MiQZkiktM99X7U/cPgw3IKpKAxQsJ5LobgZ
|
||||||
|
4P2ecv0IlN4gQb+x+lycxl93E9sJ
|
||||||
|
-----END JESS SIGNATURE-----
|
1
cmd/testdata/test3.txt
vendored
Normal file
1
cmd/testdata/test3.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hello world!!
|
9
cmd/testdata/test3.txt.sig
vendored
Normal file
9
cmd/testdata/test3.txt.sig
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
-----BEGIN JESS SIGNATURE-----
|
||||||
|
Q6VnVmVyc2lvbgFnU3VpdGVJRGtzaWduZmlsZV92MWVOb25jZUQJ9s/nZERhdGFY
|
||||||
|
d02Dq0xhYmVsZWRIYXNoxCIJILtKnL1AHj7YubrWdLu1D+voud8Ky04vh756eTae
|
||||||
|
rWQwqFNpZ25lZEF01v9izC6hqE1ldGFEYXRhgqd2ZXJzaW9upTAuMC4xqmlkZW50
|
||||||
|
aWZpZXKyd2luZG93cy9jb2RlL3RoaW5nalNpZ25hdHVyZXOBo2ZTY2hlbWVnRWQy
|
||||||
|
NTUxOWJJRHgkMzkxMWM4NGMtNzhmNy00MzU0LWE3ZjUtMGUxMTVhYTI5MDNjZVZh
|
||||||
|
bHVlWEBLsd2QbM7VmEsnW60hHn/V6EP2mGFauWZgbEOlKTiqumVFbWU4K7Fi91KL
|
||||||
|
Zgvwj+CNdZJ7Xv2qR7etviRDCmwC
|
||||||
|
-----END JESS SIGNATURE-----
|
1
cmd/testdata/test4.txt
vendored
Normal file
1
cmd/testdata/test4.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hello world!
|
1
cmd/testdata/testdir/test2.txt
vendored
Normal file
1
cmd/testdata/testdir/test2.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hello world!
|
9
cmd/testdata/testdir/test2.txt.sig
vendored
Normal file
9
cmd/testdata/testdir/test2.txt.sig
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
-----BEGIN JESS SIGNATURE-----
|
||||||
|
Q6VnVmVyc2lvbgFnU3VpdGVJRGtzaWduZmlsZV92MWVOb25jZUThzxO6ZERhdGFY
|
||||||
|
d02Dq0xhYmVsZWRIYXNoxCIJIOz3Afcn2eLXfEqkmsb7vMmXJ4rKAQvd7rlhwQz1
|
||||||
|
TUNaqFNpZ25lZEF01v9izC3SqE1ldGFEYXRhgqd2ZXJzaW9upTAuMC4xqmlkZW50
|
||||||
|
aWZpZXKyd2luZG93cy9jb2RlL3RoaW5nalNpZ25hdHVyZXOBo2ZTY2hlbWVnRWQy
|
||||||
|
NTUxOWJJRHgkMzkxMWM4NGMtNzhmNy00MzU0LWE3ZjUtMGUxMTVhYTI5MDNjZVZh
|
||||||
|
bHVlWEAGLkIoej0+ilJrIyb+BzX8+Yw2LY0zkoL9vwI02/2KqKVT7/pH+LTDX1Hl
|
||||||
|
h1epYkF8ICdwa1iVNDx6P7iNmWkL
|
||||||
|
-----END JESS SIGNATURE-----
|
81
envelope.go
81
envelope.go
|
@ -3,6 +3,10 @@ package jess
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/mr-tron/base58"
|
||||||
|
|
||||||
|
"github.com/safing/portbase/formats/dsd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Envelope holds configuration for jess to put data into a letter.
|
// Envelope holds configuration for jess to put data into a letter.
|
||||||
|
@ -268,3 +272,80 @@ func fillPassword(signet *Signet, createPassword bool, storage TrustStore, minSe
|
||||||
}
|
}
|
||||||
return getPasswordCallback(signet)
|
return getPasswordCallback(signet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CleanSignets cleans all the signets from all the non-necessary data as well
|
||||||
|
// as key material.
|
||||||
|
// This is for preparing for serializing and saving the signet.
|
||||||
|
func (e *Envelope) CleanSignets() {
|
||||||
|
for i, signet := range e.Secrets {
|
||||||
|
e.Secrets[i] = &Signet{
|
||||||
|
Version: signet.Version,
|
||||||
|
ID: signet.ID,
|
||||||
|
Scheme: signet.Scheme,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, signet := range e.Senders {
|
||||||
|
e.Secrets[i] = &Signet{
|
||||||
|
Version: signet.Version,
|
||||||
|
ID: signet.ID,
|
||||||
|
Scheme: signet.Scheme,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, signet := range e.Recipients {
|
||||||
|
e.Secrets[i] = &Signet{
|
||||||
|
Version: signet.Version,
|
||||||
|
ID: signet.ID,
|
||||||
|
Scheme: signet.Scheme,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToBytes serializes the envelope to a byte slice.
|
||||||
|
func (e *Envelope) ToBytes() ([]byte, error) {
|
||||||
|
// Minimize data and remove any key material.
|
||||||
|
e.CleanSignets()
|
||||||
|
|
||||||
|
// Serialize envelope.
|
||||||
|
data, err := dsd.Dump(e, dsd.CBOR)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to serialize the envelope: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnvelopeFromBytes parses and loads a serialized envelope.
|
||||||
|
func EnvelopeFromBytes(data []byte) (*Envelope, error) {
|
||||||
|
e := &Envelope{}
|
||||||
|
|
||||||
|
// Parse envelope from data.
|
||||||
|
if _, err := dsd.Load(data, e); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse data format: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return e, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToBase58 serializes the envelope and encodes it with base58.
|
||||||
|
func (e *Envelope) ToBase58() (string, error) {
|
||||||
|
// Serialize Signet.
|
||||||
|
data, err := e.ToBytes()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode and return.
|
||||||
|
return base58.Encode(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnvelopeFromBase58 parses and loads a base58 encoded serialized envelope.
|
||||||
|
func EnvelopeFromBase58(base58Encoded string) (*Envelope, error) {
|
||||||
|
// Decode string.
|
||||||
|
data, err := base58.Decode(base58Encoded)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode base58: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse and return.
|
||||||
|
return EnvelopeFromBytes(data)
|
||||||
|
}
|
||||||
|
|
192
import_export.go
Normal file
192
import_export.go
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
package jess
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExportSenderKeyword = "sender"
|
||||||
|
ExportSenderPrefix = "sender:"
|
||||||
|
|
||||||
|
ExportRecipientKeyword = "recipient"
|
||||||
|
ExportRecipientPrefix = "recipient:"
|
||||||
|
|
||||||
|
ExportKeyKeyword = "secret"
|
||||||
|
ExportKeyPrefix = "secret:"
|
||||||
|
|
||||||
|
ExportEnvelopeKeyword = "envelope"
|
||||||
|
ExportEnvelopePrefix = "envelope:"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Export exports the public part of a signet in text format.
|
||||||
|
func (signet *Signet) Export(short bool) (textFormat string, err error) {
|
||||||
|
// Make public if needed.
|
||||||
|
if !signet.Public {
|
||||||
|
signet, err = signet.AsRecipient()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform to text format.
|
||||||
|
return signet.toTextFormat(short)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup exports the private part of a signet in text format.
|
||||||
|
func (signet *Signet) Backup(short bool) (textFormat string, err error) {
|
||||||
|
// Abprt if public.
|
||||||
|
if signet.Public {
|
||||||
|
return "", errors.New("cannot backup (only export) a recipient")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform to text format.
|
||||||
|
return signet.toTextFormat(short)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (signet *Signet) toTextFormat(short bool) (textFormat string, err error) {
|
||||||
|
// Serialize to base58.
|
||||||
|
base58data, err := signet.ToBase58()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define keywords.
|
||||||
|
var keyword, typeComment string
|
||||||
|
switch {
|
||||||
|
case signet.Scheme == SignetSchemePassword:
|
||||||
|
return "", errors.New("cannot backup or export passwords")
|
||||||
|
case signet.Scheme == SignetSchemeKey:
|
||||||
|
// Check if the signet is marked as "public".
|
||||||
|
if signet.Public {
|
||||||
|
return "", errors.New("cannot export keys")
|
||||||
|
}
|
||||||
|
keyword = ExportKeyKeyword
|
||||||
|
typeComment = "symmetric-key"
|
||||||
|
case signet.Public:
|
||||||
|
keyword = ExportRecipientKeyword
|
||||||
|
typeComment = fmt.Sprintf(
|
||||||
|
"public-%s-key", toTextFormatString(signet.Scheme),
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
keyword = ExportSenderKeyword
|
||||||
|
typeComment = fmt.Sprintf(
|
||||||
|
"private-%s-key", toTextFormatString(signet.Scheme),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform to text format.
|
||||||
|
if short {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%s:%s",
|
||||||
|
keyword,
|
||||||
|
base58data,
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%s:%s:%s:%s",
|
||||||
|
keyword,
|
||||||
|
typeComment,
|
||||||
|
toTextFormatString(signet.Info.Name),
|
||||||
|
base58data,
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export exports the envelope in text format.
|
||||||
|
func (e *Envelope) Export(short bool) (textFormat string, err error) {
|
||||||
|
// Remove and key data.
|
||||||
|
e.CleanSignets()
|
||||||
|
|
||||||
|
// Serialize to base58.
|
||||||
|
base58data, err := e.ToBase58()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform to text format.
|
||||||
|
if short {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%s:%s",
|
||||||
|
ExportEnvelopeKeyword,
|
||||||
|
base58data,
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%s:%s:%s:%s",
|
||||||
|
ExportEnvelopeKeyword,
|
||||||
|
e.SuiteID,
|
||||||
|
e.Name,
|
||||||
|
base58data,
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyFromTextFormat loads a secret key from the text format.
|
||||||
|
func KeyFromTextFormat(textFormat string) (*Signet, error) {
|
||||||
|
// Check the identifier.
|
||||||
|
if !strings.HasPrefix(textFormat, ExportKeyPrefix) {
|
||||||
|
return nil, errors.New("not a secret")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the data section.
|
||||||
|
splitted := strings.Split(textFormat, ":")
|
||||||
|
if len(splitted) < 2 {
|
||||||
|
return nil, errors.New("invalid format")
|
||||||
|
}
|
||||||
|
return SignetFromBase58(splitted[len(splitted)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// SenderFromTextFormat loads a sender (private key) from the text format.
|
||||||
|
func SenderFromTextFormat(textFormat string) (*Signet, error) {
|
||||||
|
// Check the identifier.
|
||||||
|
if !strings.HasPrefix(textFormat, ExportSenderPrefix) {
|
||||||
|
return nil, errors.New("not a sender")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the data section.
|
||||||
|
splitted := strings.Split(textFormat, ":")
|
||||||
|
if len(splitted) < 2 {
|
||||||
|
return nil, errors.New("invalid format")
|
||||||
|
}
|
||||||
|
return SignetFromBase58(splitted[len(splitted)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecipientFromTextFormat loads a recipient (public key) from the text format.
|
||||||
|
func RecipientFromTextFormat(textFormat string) (*Signet, error) {
|
||||||
|
// Check the identifier.
|
||||||
|
if !strings.HasPrefix(textFormat, ExportRecipientPrefix) {
|
||||||
|
return nil, errors.New("not a recipient")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the data section.
|
||||||
|
splitted := strings.Split(textFormat, ":")
|
||||||
|
if len(splitted) < 2 {
|
||||||
|
return nil, errors.New("invalid format")
|
||||||
|
}
|
||||||
|
return SignetFromBase58(splitted[len(splitted)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnvelopeFromTextFormat loads an envelope from the text format.
|
||||||
|
func EnvelopeFromTextFormat(textFormat string) (*Envelope, error) {
|
||||||
|
// Check the identifier.
|
||||||
|
if !strings.HasPrefix(textFormat, ExportEnvelopePrefix) {
|
||||||
|
return nil, errors.New("not an envelope")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the data section.
|
||||||
|
splitted := strings.Split(textFormat, ":")
|
||||||
|
if len(splitted) < 2 {
|
||||||
|
return nil, errors.New("invalid format")
|
||||||
|
}
|
||||||
|
return EnvelopeFromBase58(splitted[len(splitted)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
var replaceForTextFormatMatcher = regexp.MustCompile(`[^A-Za-z\-]+`)
|
||||||
|
|
||||||
|
// toTextFormatString makes a string compatible with the text format.
|
||||||
|
func toTextFormatString(s string) string {
|
||||||
|
return strings.ToLower(
|
||||||
|
replaceForTextFormatMatcher.ReplaceAllString(s, "_"),
|
||||||
|
)
|
||||||
|
}
|
|
@ -136,6 +136,14 @@ func (signet *Signet) SetLoadedKeys(pubKey crypto.PublicKey, privKey crypto.Priv
|
||||||
|
|
||||||
// AsRecipient returns a public version of the Signet.
|
// AsRecipient returns a public version of the Signet.
|
||||||
func (signet *Signet) AsRecipient() (*Signet, error) {
|
func (signet *Signet) AsRecipient() (*Signet, error) {
|
||||||
|
// Check special signet schemes.
|
||||||
|
switch signet.Scheme {
|
||||||
|
case SignetSchemeKey:
|
||||||
|
return nil, errors.New("keys cannot be a recipient")
|
||||||
|
case SignetSchemePassword:
|
||||||
|
return nil, errors.New("passwords cannot be a recipient")
|
||||||
|
}
|
||||||
|
|
||||||
// load so we can split keys
|
// load so we can split keys
|
||||||
err := signet.LoadKey()
|
err := signet.LoadKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Add table
Reference in a new issue