diff --git a/principal/principal.go b/principal/principal.go index 63b9988..1e40d8d 100644 --- a/principal/principal.go +++ b/principal/principal.go @@ -13,7 +13,7 @@ import ( ) // AnonymousID is used for the anonymous caller. It can be used in call and query requests without a signature. -var AnonymousID = Principal{[]byte{0x04}} +var AnonymousID = Principal{Raw: []byte{0x04}} var encoding = base32.StdEncoding.WithPadding(base32.NoPadding) @@ -46,6 +46,38 @@ func MustDecode(s string) Principal { return p } +// IsOpaque checks if the principal is opaque, these are always generated by the IC and have no structure of interest +// outside of it. +func (p Principal) IsOpaque() bool { + return p.Raw[len(p.Raw)-1] == 0x01 +} + +// IsSelfAuthenticating checks if the principal is self authenticating, an external user can use these ids as the sender +// of a request if they own the corresponding private key. +func (p Principal) IsSelfAuthenticating() bool { + return p.Raw[len(p.Raw)-1] == 0x02 +} + +// IsDerived checks if the principal is derived. +func (p Principal) IsDerived() bool { + return p.Raw[len(p.Raw)-1] == 0x03 +} + +// IsAnonymous checks if the principal is the anonymous id. +func (p Principal) IsAnonymous() bool { + return bytes.Equal(p.Raw, AnonymousID.Raw) +} + +// IsReserved checks if the principal is reserved. These ids can be useful for applications that want to re-use the +// Textual representation of principals but want to indicate explicitly that the blob does not address any canisters or +// a user. +func (p Principal) IsReserved() bool { + if 29 < len(p.Raw) { + return false + } + return p.Raw[len(p.Raw)-1] == 0x7f +} + // Decode converts a textual representation into a principal. func Decode(s string) (Principal, error) { p := strings.Split(s, "-") diff --git a/principal/principal_test.go b/principal/principal_test.go index 9b43eb7..a74566d 100644 --- a/principal/principal_test.go +++ b/principal/principal_test.go @@ -3,6 +3,8 @@ package principal_test import ( "encoding/hex" "fmt" + "github.com/aviate-labs/agent-go/ic" + "testing" "github.com/aviate-labs/agent-go/principal" ) @@ -16,8 +18,23 @@ func ExampleDecode() { func ExamplePrincipal() { raw, _ := hex.DecodeString("abcd01") - p := principal.Principal{raw} + p := principal.Principal{Raw: raw} fmt.Println(p.Encode()) // Output: // em77e-bvlzu-aq } + +func TestPrincipal(t *testing.T) { + if !ic.LEDGER_PRINCIPAL.IsOpaque() { + t.Fatal("expected opaque principal") + } + if !principal.MustDecode("g27xm-fnyhk-uu73a-njpqd-hec7y-syhwe-bd45b-qm6yc-xikg5-cylqt-iae").IsSelfAuthenticating() { + t.Fatal("expected derived principal") + } + if !principal.AnonymousID.IsAnonymous() { + t.Fatal("expected anonymous principal") + } + if !(principal.Principal{Raw: append([]byte("random"), 0x7f)}).IsReserved() { + t.Fatal("expected reserved principal") + } +}