refactor(main): extract types into separate package
This commit is contained in:
186
main.go
186
main.go
@@ -9,127 +9,25 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"enclave/internal/keybase"
|
"enclave/internal/keybase"
|
||||||
|
"enclave/internal/types"
|
||||||
|
|
||||||
"github.com/extism/go-pdk"
|
"github.com/extism/go-pdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GenerateInput represents the input for the generate function
|
var enclave = &struct {
|
||||||
type GenerateInput struct {
|
|
||||||
Credential string `json:"credential"` // Base64-encoded PublicKeyCredential
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateOutput represents the output of the generate function
|
|
||||||
type GenerateOutput struct {
|
|
||||||
DID string `json:"did"`
|
|
||||||
Database []byte `json:"database"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadInput represents the input for the load function
|
|
||||||
type LoadInput struct {
|
|
||||||
Database []byte `json:"database"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadOutput represents the output of the load function
|
|
||||||
type LoadOutput struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
DID string `json:"did,omitempty"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecInput represents the input for the exec function
|
|
||||||
type ExecInput struct {
|
|
||||||
Filter string `json:"filter"` // GitHub-style filter: "resource:accounts action:sign"
|
|
||||||
Token string `json:"token"` // UCAN token for authorization
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecOutput represents the output of the exec function
|
|
||||||
type ExecOutput struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Result json.RawMessage `json:"result,omitempty"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryInput represents the input for the query function
|
|
||||||
type QueryInput struct {
|
|
||||||
DID string `json:"did"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryOutput represents the output of the query function
|
|
||||||
type QueryOutput struct {
|
|
||||||
DID string `json:"did"`
|
|
||||||
Controller string `json:"controller"`
|
|
||||||
VerificationMethods []VerificationMethod `json:"verification_methods"`
|
|
||||||
Accounts []Account `json:"accounts"`
|
|
||||||
Credentials []Credential `json:"credentials"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerificationMethod represents a DID verification method
|
|
||||||
type VerificationMethod struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Controller string `json:"controller"`
|
|
||||||
PublicKey string `json:"public_key"`
|
|
||||||
Purpose string `json:"purpose"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Account represents a derived blockchain account
|
|
||||||
type Account struct {
|
|
||||||
Address string `json:"address"`
|
|
||||||
ChainID string `json:"chain_id"`
|
|
||||||
CoinType int `json:"coin_type"`
|
|
||||||
AccountIndex int `json:"account_index"`
|
|
||||||
AddressIndex int `json:"address_index"`
|
|
||||||
Label string `json:"label"`
|
|
||||||
IsDefault bool `json:"is_default"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Credential represents a WebAuthn credential
|
|
||||||
type Credential struct {
|
|
||||||
CredentialID string `json:"credential_id"`
|
|
||||||
DeviceName string `json:"device_name"`
|
|
||||||
DeviceType string `json:"device_type"`
|
|
||||||
Authenticator string `json:"authenticator"`
|
|
||||||
Transports []string `json:"transports"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
LastUsed string `json:"last_used"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// FilterParams parsed from GitHub-style filter syntax
|
|
||||||
type FilterParams struct {
|
|
||||||
Resource string
|
|
||||||
Action string
|
|
||||||
Subject string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enclave holds the plugin state
|
|
||||||
type Enclave struct {
|
|
||||||
initialized bool
|
initialized bool
|
||||||
did string
|
did string
|
||||||
}
|
}{}
|
||||||
|
|
||||||
var enclave = &Enclave{}
|
|
||||||
|
|
||||||
func main() {}
|
func main() {}
|
||||||
|
|
||||||
// PingInput represents the input for the ping function
|
|
||||||
type PingInput struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PingOutput represents the output of the ping function
|
|
||||||
type PingOutput struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
Echo string `json:"echo"`
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:wasmexport ping
|
//go:wasmexport ping
|
||||||
func ping() int32 {
|
func ping() int32 {
|
||||||
pdk.Log(pdk.LogInfo, "ping: received request")
|
pdk.Log(pdk.LogInfo, "ping: received request")
|
||||||
|
|
||||||
var input PingInput
|
var input types.PingInput
|
||||||
if err := pdk.InputJSON(&input); err != nil {
|
if err := pdk.InputJSON(&input); err != nil {
|
||||||
output := PingOutput{
|
output := types.PingOutput{
|
||||||
Success: false,
|
Success: false,
|
||||||
Message: fmt.Sprintf("failed to parse input: %s", err),
|
Message: fmt.Sprintf("failed to parse input: %s", err),
|
||||||
}
|
}
|
||||||
@@ -137,7 +35,7 @@ func ping() int32 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
output := PingOutput{
|
output := types.PingOutput{
|
||||||
Success: true,
|
Success: true,
|
||||||
Message: "pong",
|
Message: "pong",
|
||||||
Echo: input.Message,
|
Echo: input.Message,
|
||||||
@@ -156,7 +54,7 @@ func ping() int32 {
|
|||||||
func generate() int32 {
|
func generate() int32 {
|
||||||
pdk.Log(pdk.LogInfo, "generate: starting database initialization")
|
pdk.Log(pdk.LogInfo, "generate: starting database initialization")
|
||||||
|
|
||||||
var input GenerateInput
|
var input types.GenerateInput
|
||||||
if err := pdk.InputJSON(&input); err != nil {
|
if err := pdk.InputJSON(&input); err != nil {
|
||||||
pdk.SetError(fmt.Errorf("generate: failed to parse input: %w", err))
|
pdk.SetError(fmt.Errorf("generate: failed to parse input: %w", err))
|
||||||
return 1
|
return 1
|
||||||
@@ -188,7 +86,7 @@ func generate() int32 {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
output := GenerateOutput{
|
output := types.GenerateOutput{
|
||||||
DID: did,
|
DID: did,
|
||||||
Database: dbBytes,
|
Database: dbBytes,
|
||||||
}
|
}
|
||||||
@@ -206,7 +104,7 @@ func generate() int32 {
|
|||||||
func load() int32 {
|
func load() int32 {
|
||||||
pdk.Log(pdk.LogInfo, "load: loading database from buffer")
|
pdk.Log(pdk.LogInfo, "load: loading database from buffer")
|
||||||
|
|
||||||
var input LoadInput
|
var input types.LoadInput
|
||||||
if err := pdk.InputJSON(&input); err != nil {
|
if err := pdk.InputJSON(&input); err != nil {
|
||||||
pdk.SetError(fmt.Errorf("load: failed to parse input: %w", err))
|
pdk.SetError(fmt.Errorf("load: failed to parse input: %w", err))
|
||||||
return 1
|
return 1
|
||||||
@@ -219,7 +117,7 @@ func load() int32 {
|
|||||||
|
|
||||||
did, err := loadDatabase(input.Database)
|
did, err := loadDatabase(input.Database)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
output := LoadOutput{
|
output := types.LoadOutput{
|
||||||
Success: false,
|
Success: false,
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
}
|
}
|
||||||
@@ -230,7 +128,7 @@ func load() int32 {
|
|||||||
enclave.initialized = true
|
enclave.initialized = true
|
||||||
enclave.did = did
|
enclave.did = did
|
||||||
|
|
||||||
output := LoadOutput{
|
output := types.LoadOutput{
|
||||||
Success: true,
|
Success: true,
|
||||||
DID: did,
|
DID: did,
|
||||||
}
|
}
|
||||||
@@ -249,34 +147,34 @@ func exec() int32 {
|
|||||||
pdk.Log(pdk.LogInfo, "exec: executing action")
|
pdk.Log(pdk.LogInfo, "exec: executing action")
|
||||||
|
|
||||||
if !enclave.initialized {
|
if !enclave.initialized {
|
||||||
output := ExecOutput{Success: false, Error: "database not initialized, call generate or load first"}
|
output := types.ExecOutput{Success: false, Error: "database not initialized, call generate or load first"}
|
||||||
pdk.OutputJSON(output)
|
pdk.OutputJSON(output)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
var input ExecInput
|
var input types.ExecInput
|
||||||
if err := pdk.InputJSON(&input); err != nil {
|
if err := pdk.InputJSON(&input); err != nil {
|
||||||
output := ExecOutput{Success: false, Error: fmt.Sprintf("failed to parse input: %s", err)}
|
output := types.ExecOutput{Success: false, Error: fmt.Sprintf("failed to parse input: %s", err)}
|
||||||
pdk.OutputJSON(output)
|
pdk.OutputJSON(output)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if input.Filter == "" {
|
if input.Filter == "" {
|
||||||
output := ExecOutput{Success: false, Error: "filter is required"}
|
output := types.ExecOutput{Success: false, Error: "filter is required"}
|
||||||
pdk.OutputJSON(output)
|
pdk.OutputJSON(output)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
params, err := parseFilter(input.Filter)
|
params, err := parseFilter(input.Filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
output := ExecOutput{Success: false, Error: fmt.Sprintf("invalid filter: %s", err)}
|
output := types.ExecOutput{Success: false, Error: fmt.Sprintf("invalid filter: %s", err)}
|
||||||
pdk.OutputJSON(output)
|
pdk.OutputJSON(output)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if input.Token != "" {
|
if input.Token != "" {
|
||||||
if err := validateUCAN(input.Token, params); err != nil {
|
if err := validateUCAN(input.Token, params); err != nil {
|
||||||
output := ExecOutput{
|
output := types.ExecOutput{
|
||||||
Success: false,
|
Success: false,
|
||||||
Error: fmt.Sprintf("authorization failed: %s", err.Error()),
|
Error: fmt.Sprintf("authorization failed: %s", err.Error()),
|
||||||
}
|
}
|
||||||
@@ -287,7 +185,7 @@ func exec() int32 {
|
|||||||
|
|
||||||
result, err := executeAction(params)
|
result, err := executeAction(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
output := ExecOutput{
|
output := types.ExecOutput{
|
||||||
Success: false,
|
Success: false,
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
}
|
}
|
||||||
@@ -295,7 +193,7 @@ func exec() int32 {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
output := ExecOutput{
|
output := types.ExecOutput{
|
||||||
Success: true,
|
Success: true,
|
||||||
Result: result,
|
Result: result,
|
||||||
}
|
}
|
||||||
@@ -314,7 +212,7 @@ func query() int32 {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
var input QueryInput
|
var input types.QueryInput
|
||||||
if err := pdk.InputJSON(&input); err != nil {
|
if err := pdk.InputJSON(&input); err != nil {
|
||||||
pdk.SetError(fmt.Errorf("query: failed to parse input: %w", err))
|
pdk.SetError(fmt.Errorf("query: failed to parse input: %w", err))
|
||||||
return 1
|
return 1
|
||||||
@@ -388,8 +286,8 @@ func loadDatabase(data []byte) (string, error) {
|
|||||||
return did, nil
|
return did, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFilter(filter string) (*FilterParams, error) {
|
func parseFilter(filter string) (*types.FilterParams, error) {
|
||||||
params := &FilterParams{}
|
params := &types.FilterParams{}
|
||||||
parts := strings.FieldsSeq(filter)
|
parts := strings.FieldsSeq(filter)
|
||||||
|
|
||||||
for part := range parts {
|
for part := range parts {
|
||||||
@@ -419,12 +317,7 @@ func parseFilter(filter string) (*FilterParams, error) {
|
|||||||
return params, nil
|
return params, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateUCAN(token string, params *FilterParams) error {
|
func validateUCAN(token string, params *types.FilterParams) error {
|
||||||
// TODO: Decode UCAN token
|
|
||||||
// TODO: Verify signature chain
|
|
||||||
// TODO: Check capabilities match params
|
|
||||||
// TODO: Verify not expired or revoked
|
|
||||||
|
|
||||||
if token == "" {
|
if token == "" {
|
||||||
return errors.New("token is required")
|
return errors.New("token is required")
|
||||||
}
|
}
|
||||||
@@ -433,11 +326,7 @@ func validateUCAN(token string, params *FilterParams) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeAction(params *FilterParams) (json.RawMessage, error) {
|
func executeAction(params *types.FilterParams) (json.RawMessage, error) {
|
||||||
// TODO: Route to appropriate handler based on resource/action
|
|
||||||
// TODO: Execute database queries
|
|
||||||
// TODO: Return results
|
|
||||||
|
|
||||||
switch params.Resource {
|
switch params.Resource {
|
||||||
case "accounts":
|
case "accounts":
|
||||||
return executeAccountAction(params)
|
return executeAccountAction(params)
|
||||||
@@ -452,10 +341,10 @@ func executeAction(params *FilterParams) (json.RawMessage, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeAccountAction(params *FilterParams) (json.RawMessage, error) {
|
func executeAccountAction(params *types.FilterParams) (json.RawMessage, error) {
|
||||||
switch params.Action {
|
switch params.Action {
|
||||||
case "list":
|
case "list":
|
||||||
accounts := []Account{
|
accounts := []types.Account{
|
||||||
{
|
{
|
||||||
Address: "sonr1abc123...",
|
Address: "sonr1abc123...",
|
||||||
ChainID: "sonr-mainnet-1",
|
ChainID: "sonr-mainnet-1",
|
||||||
@@ -474,10 +363,10 @@ func executeAccountAction(params *FilterParams) (json.RawMessage, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeCredentialAction(params *FilterParams) (json.RawMessage, error) {
|
func executeCredentialAction(params *types.FilterParams) (json.RawMessage, error) {
|
||||||
switch params.Action {
|
switch params.Action {
|
||||||
case "list":
|
case "list":
|
||||||
credentials := []Credential{
|
credentials := []types.Credential{
|
||||||
{
|
{
|
||||||
CredentialID: "cred_abc123",
|
CredentialID: "cred_abc123",
|
||||||
DeviceName: "MacBook Pro",
|
DeviceName: "MacBook Pro",
|
||||||
@@ -494,7 +383,7 @@ func executeCredentialAction(params *FilterParams) (json.RawMessage, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeSessionAction(params *FilterParams) (json.RawMessage, error) {
|
func executeSessionAction(params *types.FilterParams) (json.RawMessage, error) {
|
||||||
switch params.Action {
|
switch params.Action {
|
||||||
case "list":
|
case "list":
|
||||||
return json.Marshal([]map[string]any{})
|
return json.Marshal([]map[string]any{})
|
||||||
@@ -507,7 +396,7 @@ func executeSessionAction(params *FilterParams) (json.RawMessage, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeGrantAction(params *FilterParams) (json.RawMessage, error) {
|
func executeGrantAction(params *types.FilterParams) (json.RawMessage, error) {
|
||||||
switch params.Action {
|
switch params.Action {
|
||||||
case "list":
|
case "list":
|
||||||
return json.Marshal([]map[string]any{})
|
return json.Marshal([]map[string]any{})
|
||||||
@@ -520,16 +409,11 @@ func executeGrantAction(params *FilterParams) (json.RawMessage, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveDID(did string) (*QueryOutput, error) {
|
func resolveDID(did string) (*types.QueryOutput, error) {
|
||||||
// TODO: Query database for DID document
|
output := &types.QueryOutput{
|
||||||
// TODO: Fetch verification methods
|
|
||||||
// TODO: Fetch associated accounts
|
|
||||||
// TODO: Fetch credentials
|
|
||||||
|
|
||||||
output := &QueryOutput{
|
|
||||||
DID: did,
|
DID: did,
|
||||||
Controller: did,
|
Controller: did,
|
||||||
VerificationMethods: []VerificationMethod{
|
VerificationMethods: []types.VerificationMethod{
|
||||||
{
|
{
|
||||||
ID: did + "#key-1",
|
ID: did + "#key-1",
|
||||||
Type: "Ed25519VerificationKey2020",
|
Type: "Ed25519VerificationKey2020",
|
||||||
@@ -538,7 +422,7 @@ func resolveDID(did string) (*QueryOutput, error) {
|
|||||||
Purpose: "authentication",
|
Purpose: "authentication",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Accounts: []Account{
|
Accounts: []types.Account{
|
||||||
{
|
{
|
||||||
Address: "sonr1abc123...",
|
Address: "sonr1abc123...",
|
||||||
ChainID: "sonr-mainnet-1",
|
ChainID: "sonr-mainnet-1",
|
||||||
@@ -549,7 +433,7 @@ func resolveDID(did string) (*QueryOutput, error) {
|
|||||||
IsDefault: true,
|
IsDefault: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Credentials: []Credential{
|
Credentials: []types.Credential{
|
||||||
{
|
{
|
||||||
CredentialID: "cred_abc123",
|
CredentialID: "cred_abc123",
|
||||||
DeviceName: "MacBook Pro",
|
DeviceName: "MacBook Pro",
|
||||||
|
|||||||
Reference in New Issue
Block a user