add private key handling
This also contains a couple fixes to the subject part.
This commit is contained in:
parent
b9c2539073
commit
bc8e1353af
|
@ -40,28 +40,16 @@ func main() {
|
||||||
err = setSubject(args, client)
|
err = setSubject(args, client)
|
||||||
case `show-subj`:
|
case `show-subj`:
|
||||||
err = showSubject(args, client)
|
err = showSubject(args, client)
|
||||||
// case `list`:
|
case `create-private`:
|
||||||
// err = listDescription(args, client)
|
err = createPrivateKey(args, client)
|
||||||
// case `create-file`:
|
case `delete-private`:
|
||||||
// err = createFile(args, client)
|
err = deletePrivateKey(args, client)
|
||||||
// case `list-files`:
|
case `list-private`:
|
||||||
// err = listFile(args, client)
|
err = listPrivateKey(args, client)
|
||||||
// case `delete-file`:
|
case `set-private`:
|
||||||
// err = deleteFile(args, client)
|
err = setPrivateKey(args, client)
|
||||||
// case `create-private-key`:
|
case `show-private`:
|
||||||
// err = createPrivateKey(args, client)
|
err = showPrivateKey(args, client)
|
||||||
// case `get-private-key`:
|
|
||||||
// err = getPrivateKey(args, client)
|
|
||||||
// case `list-private-keys`:
|
|
||||||
// err = listPrivateKey(args, client)
|
|
||||||
// case `delete-private-key`:
|
|
||||||
// err = deletePrivateKey(args, client)
|
|
||||||
// case `create-public-key`:
|
|
||||||
// err = createPublicKey(args, client)
|
|
||||||
// case `list-public-keys`:
|
|
||||||
// err = listPublicKey(args, client)
|
|
||||||
// case `delete-public-key`:
|
|
||||||
// err = deletePublicKey(args, client)
|
|
||||||
default:
|
default:
|
||||||
fmt.Printf("unknown subcommand '%s'\n", cmd)
|
fmt.Printf("unknown subcommand '%s'\n", cmd)
|
||||||
printCommands()
|
printCommands()
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"text/tabwriter"
|
||||||
|
|
||||||
|
"github.com/gibheer/pkiadm"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
flag "github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createPrivateKey(args []string, client *pkiadm.Client) error {
|
||||||
|
fs := flag.NewFlagSet("create-private", flag.ExitOnError)
|
||||||
|
fs.Usage = func() {
|
||||||
|
fmt.Printf("Usage of %s:\n", "pkiadm create-private")
|
||||||
|
fmt.Println(`
|
||||||
|
Create a new private key for different use cases. The supported types are rsa,
|
||||||
|
ecdsa and ed25519. Please keep in mind, that ed25519 is currently not supported
|
||||||
|
for certificate generation.
|
||||||
|
`)
|
||||||
|
fs.PrintDefaults()
|
||||||
|
}
|
||||||
|
pk := pkiadm.PrivateKey{}
|
||||||
|
fs.StringVar(&pk.ID, "id", "", "set the unique id for the new private key")
|
||||||
|
var pkType = fs.String("type", "rsa", "set the type of the private key (rsa, ecdsa, ed25519)")
|
||||||
|
fs.UintVar(&pk.Bits, "bits", 2048, "set the number of bits to use. For rsa it can be 1024 up to 32768, for ecdsa 224, 256, 384, 521. Ed25519 is set to 256 by default.")
|
||||||
|
fs.Parse(args)
|
||||||
|
|
||||||
|
pkT, err := pkiadm.StringToPrivateKeyType(*pkType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pk.Type = pkT
|
||||||
|
if err := client.CreatePrivateKey(pk); err != nil {
|
||||||
|
return errors.Wrap(err, "could not create private key")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func setPrivateKey(args []string, client *pkiadm.Client) error {
|
||||||
|
fs := flag.NewFlagSet("set-private", flag.ExitOnError)
|
||||||
|
pk := pkiadm.PrivateKey{}
|
||||||
|
fs.StringVar(&pk.ID, "id", "", "set the id of the private key to change")
|
||||||
|
var pkType = fs.String("type", "rsa", "set the type of the private key (rsa, ecdsa, ed25519)")
|
||||||
|
fs.UintVar(&pk.Bits, "bits", 2048, "set the number of bits to use. For rsa it can be 1024 up to 32768, for ecdsa 224, 256, 384, 521. Ed25519 is set to 256 by default.")
|
||||||
|
fs.Parse(args)
|
||||||
|
|
||||||
|
pkT, err := pkiadm.StringToPrivateKeyType(*pkType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pk.Type = pkT
|
||||||
|
|
||||||
|
fieldList := []string{}
|
||||||
|
for _, field := range []string{"type", "bits"} {
|
||||||
|
flag := fs.Lookup(field)
|
||||||
|
if flag.Changed {
|
||||||
|
fieldList = append(fieldList, field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := client.SetPrivateKey(pk, fieldList); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func deletePrivateKey(args []string, client *pkiadm.Client) error {
|
||||||
|
fs := flag.NewFlagSet("delete-private", flag.ExitOnError)
|
||||||
|
var id = fs.String("id", "", "set the id of the private key to delete")
|
||||||
|
fs.Parse(args)
|
||||||
|
|
||||||
|
if err := client.DeletePrivateKey(*id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func listPrivateKey(args []string, client *pkiadm.Client) error {
|
||||||
|
fs := flag.NewFlagSet("list-private", flag.ExitOnError)
|
||||||
|
fs.Parse(args)
|
||||||
|
|
||||||
|
pks, err := client.ListPrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pks) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := tabwriter.NewWriter(os.Stdout, 2, 2, 1, ' ', tabwriter.AlignRight)
|
||||||
|
fmt.Fprintf(out, "%s\t%s\t%s\t\n", "id", "type", "bits")
|
||||||
|
for _, pk := range pks {
|
||||||
|
fmt.Fprintf(out, "%s\t%s\t%d\t\n", pk.ID, pk.Type.String(), pk.Bits)
|
||||||
|
}
|
||||||
|
out.Flush()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func showPrivateKey(args []string, client *pkiadm.Client) error {
|
||||||
|
fs := flag.NewFlagSet("show-private", flag.ExitOnError)
|
||||||
|
var id = fs.String("id", "", "set the id of the private key to show")
|
||||||
|
fs.Parse(args)
|
||||||
|
|
||||||
|
pk, err := client.ShowPrivateKey(*id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
out := tabwriter.NewWriter(os.Stdout, 2, 2, 1, ' ', tabwriter.AlignRight)
|
||||||
|
fmt.Fprintf(out, "ID:\t%s\t\n", pk.ID)
|
||||||
|
fmt.Fprintf(out, "type:\t%s\t\n", pk.Type.String())
|
||||||
|
fmt.Fprintf(out, "bits:\t%d\t\n", pk.Bits)
|
||||||
|
fmt.Fprintf(out, "checksum:\t%s\t\n", base64.StdEncoding.EncodeToString(pk.Checksum))
|
||||||
|
out.Flush()
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -32,7 +32,6 @@ In most cases only the common name, organization name and the country is provide
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := client.CreateSubject(subj); err != nil {
|
if err := client.CreateSubject(subj); err != nil {
|
||||||
fmt.Println("got an error")
|
|
||||||
return errors.Wrap(err, "could not create new subject")
|
return errors.Wrap(err, "could not create new subject")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -6,12 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/gibheer/pki"
|
"github.com/gibheer/pki"
|
||||||
)
|
"github.com/gibheer/pkiadm"
|
||||||
|
|
||||||
const (
|
|
||||||
PKTRSA PrivateKeyType = iota
|
|
||||||
PKTECDSA
|
|
||||||
PKTED25519
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -23,24 +18,23 @@ const (
|
||||||
type (
|
type (
|
||||||
PrivateKey struct {
|
PrivateKey struct {
|
||||||
ID string
|
ID string
|
||||||
PKType PrivateKeyType
|
PKType pkiadm.PrivateKeyType
|
||||||
Length uint
|
Bits uint
|
||||||
Key []byte
|
Key []byte
|
||||||
}
|
}
|
||||||
PrivateKeyType uint
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewPrivateKey(id string, pkType PrivateKeyType, length uint) (*PrivateKey, error) {
|
func NewPrivateKey(id string, pkType pkiadm.PrivateKeyType, bits uint) (*PrivateKey, error) {
|
||||||
if id == "" {
|
if id == "" {
|
||||||
return nil, ENoIDGiven
|
return nil, ENoIDGiven
|
||||||
}
|
}
|
||||||
if err := verifyPK(pkType, length); err != nil {
|
if err := verifyPK(pkType, bits); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
pk := PrivateKey{
|
pk := PrivateKey{
|
||||||
ID: id,
|
ID: id,
|
||||||
PKType: pkType,
|
PKType: pkType,
|
||||||
Length: length,
|
Bits: bits,
|
||||||
}
|
}
|
||||||
return &pk, nil
|
return &pk, nil
|
||||||
}
|
}
|
||||||
|
@ -67,13 +61,13 @@ func (p *PrivateKey) Refresh(_ *Storage) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
switch p.PKType {
|
switch p.PKType {
|
||||||
case PKTRSA:
|
case pkiadm.PKTRSA:
|
||||||
key, err = pki.NewPrivateKeyRsa(int(p.Length))
|
key, err = pki.NewPrivateKeyRsa(int(p.Bits))
|
||||||
case PKTED25519:
|
case pkiadm.PKTED25519:
|
||||||
key, err = pki.NewPrivateKeyEd25519()
|
key, err = pki.NewPrivateKeyEd25519()
|
||||||
case PKTECDSA:
|
case pkiadm.PKTECDSA:
|
||||||
var curve elliptic.Curve
|
var curve elliptic.Curve
|
||||||
switch p.Length {
|
switch p.Bits {
|
||||||
case 224:
|
case 224:
|
||||||
curve = elliptic.P224()
|
curve = elliptic.P224()
|
||||||
case 256:
|
case 256:
|
||||||
|
@ -120,20 +114,20 @@ func (p *PrivateKey) GetKey() (pki.PrivateKey, error) {
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyPK(pkType PrivateKeyType, length uint) error {
|
func verifyPK(pkType pkiadm.PrivateKeyType, bits uint) error {
|
||||||
switch pkType {
|
switch pkType {
|
||||||
case PKTRSA:
|
case pkiadm.PKTRSA:
|
||||||
if length < 1024 || length > 32768 {
|
if bits < 1024 || bits > 32768 {
|
||||||
return ELengthOutOfBounds
|
return ELengthOutOfBounds
|
||||||
}
|
}
|
||||||
case PKTECDSA:
|
case pkiadm.PKTECDSA:
|
||||||
switch length {
|
switch bits {
|
||||||
case 224, 256, 384, 521:
|
case 224, 256, 384, 521:
|
||||||
default:
|
default:
|
||||||
return EWrongKeyLength
|
return EWrongKeyLength
|
||||||
}
|
}
|
||||||
case PKTED25519:
|
case pkiadm.PKTED25519:
|
||||||
if length != 256 {
|
if bits != 256 {
|
||||||
return EWrongKeyLengthED25519
|
return EWrongKeyLengthED25519
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -142,9 +136,92 @@ func verifyPK(pkType PrivateKeyType, length uint) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (p *PrivateKey) MarshalJSON() ([]byte, error) {
|
func (s *Server) CreatePrivateKey(inPk pkiadm.PrivateKey, res *pkiadm.Result) error {
|
||||||
// return json.Marshal(*p)
|
s.lock()
|
||||||
//}
|
defer s.unlock()
|
||||||
//func (p *PrivateKey) UnmarshalJSON(raw []byte) error {
|
|
||||||
// return json.Unmarshal(raw, p)
|
pk, err := NewPrivateKey(inPk.ID, inPk.Type, inPk.Bits)
|
||||||
//}
|
if err != nil {
|
||||||
|
res.SetError(err, "Could not create new private key '%s'", inPk.ID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := s.storage.AddPrivateKey(pk); err != nil {
|
||||||
|
res.SetError(err, "Could not add private key '%s'", inPk.ID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (s *Server) SetPrivateKey(changeset pkiadm.PrivateKeyChange, res *pkiadm.Result) error {
|
||||||
|
s.lock()
|
||||||
|
defer s.unlock()
|
||||||
|
|
||||||
|
pk, err := s.storage.GetPrivateKey(ResourceName{ID: changeset.PrivateKey.ID, Type: RTPrivateKey})
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, "Could not find private key '%s'", changeset.PrivateKey.ID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, field := range changeset.FieldList {
|
||||||
|
switch field {
|
||||||
|
case "type":
|
||||||
|
pk.PKType = changeset.PrivateKey.Type
|
||||||
|
case "bits":
|
||||||
|
pk.Bits = changeset.PrivateKey.Bits
|
||||||
|
default:
|
||||||
|
res.SetError(fmt.Errorf("unknown field"), "unknown field '%s'", field)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := s.storage.Update(ResourceName{ID: pk.ID, Type: RTPrivateKey}); err != nil {
|
||||||
|
res.SetError(err, "Could not update private key '%s'", changeset.PrivateKey.ID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return s.store(res)
|
||||||
|
}
|
||||||
|
func (s *Server) DeletePrivateKey(inPk pkiadm.ResourceName, res *pkiadm.Result) error {
|
||||||
|
s.lock()
|
||||||
|
defer s.unlock()
|
||||||
|
|
||||||
|
pk, err := s.storage.GetPrivateKey(ResourceName{ID: inPk.ID, Type: RTPrivateKey})
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, "Could not find private key '%s'", inPk.ID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.storage.Remove(pk); err != nil {
|
||||||
|
res.SetError(err, "Could not remove private key '%s'", pk.ID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return s.store(res)
|
||||||
|
}
|
||||||
|
func (s *Server) ShowPrivateKey(inPk pkiadm.ResourceName, res *pkiadm.ResultPrivateKey) error {
|
||||||
|
s.lock()
|
||||||
|
defer s.unlock()
|
||||||
|
|
||||||
|
pk, err := s.storage.GetPrivateKey(ResourceName{ID: inPk.ID, Type: RTPrivateKey})
|
||||||
|
if err != nil {
|
||||||
|
res.Result.SetError(err, "Could not find private key '%s'", inPk.ID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
res.PrivateKeys = []pkiadm.PrivateKey{pkiadm.PrivateKey{
|
||||||
|
ID: pk.ID,
|
||||||
|
Type: pk.PKType,
|
||||||
|
Bits: pk.Bits,
|
||||||
|
Checksum: pk.Checksum(),
|
||||||
|
}}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (s *Server) ListPrivateKey(filter pkiadm.Filter, res *pkiadm.ResultPrivateKey) error {
|
||||||
|
s.lock()
|
||||||
|
defer s.unlock()
|
||||||
|
|
||||||
|
for _, pk := range s.storage.PrivateKeys {
|
||||||
|
res.PrivateKeys = append(res.PrivateKeys, pkiadm.PrivateKey{
|
||||||
|
ID: pk.ID,
|
||||||
|
Type: pk.PKType,
|
||||||
|
Bits: pk.Bits,
|
||||||
|
Checksum: pk.Checksum(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/gibheer/pkiadm"
|
"github.com/gibheer/pkiadm"
|
||||||
)
|
)
|
||||||
|
@ -90,10 +91,13 @@ func (s *Server) SetSubject(changeset pkiadm.SubjectChange, res *pkiadm.Result)
|
||||||
subj.Data.StreetAddress = changes.StreetAddress
|
subj.Data.StreetAddress = changes.StreetAddress
|
||||||
case "code":
|
case "code":
|
||||||
subj.Data.PostalCode = changes.PostalCode
|
subj.Data.PostalCode = changes.PostalCode
|
||||||
|
default:
|
||||||
|
res.SetError(fmt.Errorf("unknown field"), "unknown field '%s'", field)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := s.storage.Update(ResourceName{ID: subj.ID, Type: RTSubject}); err != nil {
|
if err := s.storage.Update(ResourceName{ID: subj.ID, Type: RTSubject}); err != nil {
|
||||||
res.SetError(err, "Could update resource '%s'", changeset.Subject.ID)
|
res.SetError(err, "Could not update subject '%s'", changeset.Subject.ID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return s.store(res)
|
return s.store(res)
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package pkiadm
|
||||||
|
|
||||||
|
const (
|
||||||
|
PKTRSA PrivateKeyType = iota
|
||||||
|
PKTECDSA
|
||||||
|
PKTED25519
|
||||||
|
PKTUnknown
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
PrivateKey struct {
|
||||||
|
ID string
|
||||||
|
Type PrivateKeyType
|
||||||
|
Bits uint
|
||||||
|
Checksum []byte // This field is only set by the server
|
||||||
|
}
|
||||||
|
PrivateKeyChange struct {
|
||||||
|
PrivateKey PrivateKey
|
||||||
|
FieldList []string
|
||||||
|
}
|
||||||
|
ResultPrivateKey struct {
|
||||||
|
Result Result
|
||||||
|
PrivateKeys []PrivateKey
|
||||||
|
}
|
||||||
|
PrivateKeyType uint
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreatePrivateKey sends a RPC request to create a new private key.
|
||||||
|
func (c *Client) CreatePrivateKey(pk PrivateKey) error {
|
||||||
|
return c.exec("CreatePrivateKey", pk)
|
||||||
|
}
|
||||||
|
func (c *Client) SetPrivateKey(pk PrivateKey, fieldList []string) error {
|
||||||
|
changeset := PrivateKeyChange{pk, fieldList}
|
||||||
|
return c.exec("SetPrivateKey", changeset)
|
||||||
|
}
|
||||||
|
func (c *Client) DeletePrivateKey(id string) error {
|
||||||
|
pk := ResourceName{ID: id, Type: RTPrivateKey}
|
||||||
|
return c.exec("DeletePrivateKey", pk)
|
||||||
|
}
|
||||||
|
func (c *Client) ListPrivateKey() ([]PrivateKey, error) {
|
||||||
|
result := &ResultPrivateKey{}
|
||||||
|
if err := c.query("ListPrivateKey", Filter{}, result); err != nil {
|
||||||
|
return []PrivateKey{}, err
|
||||||
|
}
|
||||||
|
if result.Result.HasError {
|
||||||
|
return []PrivateKey{}, result.Result.Error
|
||||||
|
}
|
||||||
|
return result.PrivateKeys, nil
|
||||||
|
}
|
||||||
|
func (c *Client) ShowPrivateKey(id string) (PrivateKey, error) {
|
||||||
|
pk := ResourceName{ID: id, Type: RTPrivateKey}
|
||||||
|
result := &ResultPrivateKey{}
|
||||||
|
if err := c.query("ShowPrivateKey", pk, result); err != nil {
|
||||||
|
return PrivateKey{}, err
|
||||||
|
}
|
||||||
|
if result.Result.HasError {
|
||||||
|
return PrivateKey{}, result.Result.Error
|
||||||
|
}
|
||||||
|
for _, privateKey := range result.PrivateKeys {
|
||||||
|
return privateKey, nil
|
||||||
|
}
|
||||||
|
return PrivateKey{}, nil
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Code generated by "stringer -type PrivateKeyType"; DO NOT EDIT
|
||||||
|
|
||||||
|
package pkiadm
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
const _PrivateKeyType_name = "rsaecdsaed25519"
|
||||||
|
|
||||||
|
var _PrivateKeyType_index = [...]uint8{0, 3, 8, 15}
|
||||||
|
|
||||||
|
func (i PrivateKeyType) String() string {
|
||||||
|
if i >= PrivateKeyType(len(_PrivateKeyType_index)-1) {
|
||||||
|
return fmt.Sprintf("PrivateKeyType(%d)", i)
|
||||||
|
}
|
||||||
|
return _PrivateKeyType_name[_PrivateKeyType_index[i]:_PrivateKeyType_index[i+1]]
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringToPrivateKeyType(t string) (PrivateKeyType, error) {
|
||||||
|
switch t {
|
||||||
|
case "rsa":
|
||||||
|
return PKTRSA, nil
|
||||||
|
case "ecdsa":
|
||||||
|
return PKTECDSA, nil
|
||||||
|
case "ed25519":
|
||||||
|
return PKTED25519, nil
|
||||||
|
default:
|
||||||
|
return PKTUnknown, fmt.Errorf("unknown private key type")
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,7 +39,7 @@ func (c *Client) ShowSubject(id string) (Subject, error) {
|
||||||
subj := ResourceName{ID: id, Type: RTSubject}
|
subj := ResourceName{ID: id, Type: RTSubject}
|
||||||
result := &ResultSubjects{}
|
result := &ResultSubjects{}
|
||||||
if err := c.query("ShowSubject", subj, result); err != nil {
|
if err := c.query("ShowSubject", subj, result); err != nil {
|
||||||
return Subject{}, nil
|
return Subject{}, err
|
||||||
}
|
}
|
||||||
if result.Result.HasError {
|
if result.Result.HasError {
|
||||||
return Subject{}, result.Result.Error
|
return Subject{}, result.Result.Error
|
||||||
|
|
Loading…
Reference in New Issue