Implement federation node pairing flow
This commit is contained in:
committed by
Peter Grlica
parent
27463443bd
commit
37e060a576
@@ -5,79 +5,106 @@
|
||||
# Next step: swagger.
|
||||
|
||||
endpoints:
|
||||
- title: Node identity
|
||||
path: "/node/identity"
|
||||
entrypoint: identity
|
||||
authentication: []
|
||||
- title: Federation node handshake
|
||||
path: "/nodes/{nodeID}/handshake"
|
||||
entrypoint: nodeHandshake
|
||||
parameters:
|
||||
path:
|
||||
- name: nodeID
|
||||
type: uint64
|
||||
required: true
|
||||
title: NodeID
|
||||
apis:
|
||||
- name: generate node identity
|
||||
- name: initialize
|
||||
method: POST
|
||||
title: Generate an origin node identity
|
||||
path: "/generate"
|
||||
title: Initialize the handshake step with node B
|
||||
path: ""
|
||||
parameters:
|
||||
post:
|
||||
- name: domain
|
||||
- name: nodeURI
|
||||
type: string
|
||||
required: true
|
||||
title: Domain of the destination node
|
||||
|
||||
- name: register origin node
|
||||
method: POST
|
||||
title: Register a new origin node
|
||||
path: "/register"
|
||||
parameters:
|
||||
post:
|
||||
- name: identifier
|
||||
title: Node A node URI
|
||||
- name: tokenB
|
||||
type: string
|
||||
required: true
|
||||
title: Origin node identifier
|
||||
|
||||
- title: Federation node pair request
|
||||
path: "/node/pair/request"
|
||||
entrypoint: pairRequest
|
||||
authentication: []
|
||||
apis:
|
||||
- name: request pairing
|
||||
method: POST
|
||||
title: Handle destination node pair request
|
||||
path: "/"
|
||||
parameters:
|
||||
post:
|
||||
- name: identifier
|
||||
type: string
|
||||
required: true
|
||||
title: Origin node identifier
|
||||
- name: token
|
||||
type: string
|
||||
required: true
|
||||
title: Destination node token
|
||||
|
||||
- title: Federation node pairing
|
||||
path: "/node/pair"
|
||||
entrypoint: pair
|
||||
authentication: []
|
||||
apis:
|
||||
- name: approve pairing
|
||||
method: POST
|
||||
title: Approve the destination node pair request
|
||||
path: "/approve"
|
||||
parameters:
|
||||
get:
|
||||
- name: requestID
|
||||
title: Node B auth token
|
||||
- name: nodeIDB
|
||||
type: uint64
|
||||
required: true
|
||||
title: Pair requestID
|
||||
title: Node B nodeID
|
||||
|
||||
- name: complete pairing
|
||||
- title: Federation nodes
|
||||
path: "/nodes"
|
||||
entrypoint: node
|
||||
apis:
|
||||
- name: create
|
||||
method: POST
|
||||
title: Complete pairing with the origin
|
||||
path: "/complete"
|
||||
title: Create a new federation node
|
||||
path: ""
|
||||
parameters:
|
||||
post:
|
||||
- name: token
|
||||
# @todo remove this
|
||||
- name: myDomain
|
||||
type: string
|
||||
required: false
|
||||
title: "[TMP] field that determines my domain"
|
||||
|
||||
- name: domain
|
||||
type: string
|
||||
required: false
|
||||
title: Node B domain
|
||||
- name: name
|
||||
type: string
|
||||
required: false
|
||||
title: Name for this node
|
||||
- name: adminContact
|
||||
type: string
|
||||
required: false
|
||||
title: Node B admin contact email
|
||||
- name: nodeURI
|
||||
type: string
|
||||
required: false
|
||||
title: Node A URI
|
||||
|
||||
- name: pair
|
||||
method: POST
|
||||
title: Initialize the pairing process between the two nodes
|
||||
path: "/{nodeID}/pair"
|
||||
parameters:
|
||||
path:
|
||||
- name: nodeID
|
||||
type: uint64
|
||||
required: true
|
||||
title: NodeID
|
||||
|
||||
- name: handshake confirm
|
||||
method: POST
|
||||
title: Confirm the requested handshake
|
||||
path: "/{nodeID}/handshake-confirm"
|
||||
parameters:
|
||||
path:
|
||||
- name: nodeID
|
||||
type: uint64
|
||||
required: true
|
||||
title: NodeID
|
||||
|
||||
- name: handshake complete
|
||||
method: POST
|
||||
title: Complete the handshake
|
||||
path: "/{nodeID}/handshake-complete"
|
||||
parameters:
|
||||
path:
|
||||
- name: nodeID
|
||||
type: uint64
|
||||
required: true
|
||||
title: NodeID
|
||||
|
||||
post:
|
||||
- name: tokenA
|
||||
type: string
|
||||
required: true
|
||||
title: Auth token of the origin node
|
||||
title: Node A token
|
||||
|
||||
- title: Manage structure
|
||||
description: Manage structure
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
package handlers
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
// Definitions file that controls how this file is generated:
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/pkg/logger"
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
IdentityAPI interface {
|
||||
GenerateNodeIdentity(context.Context, *request.IdentityGenerateNodeIdentity) (interface{}, error)
|
||||
RegisterOriginNode(context.Context, *request.IdentityRegisterOriginNode) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
Identity struct {
|
||||
GenerateNodeIdentity func(http.ResponseWriter, *http.Request)
|
||||
RegisterOriginNode func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
)
|
||||
|
||||
func NewIdentity(h IdentityAPI) *Identity {
|
||||
return &Identity{
|
||||
GenerateNodeIdentity: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewIdentityGenerateNodeIdentity()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("Identity.GenerateNodeIdentity", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.GenerateNodeIdentity(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("Identity.GenerateNodeIdentity", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("Identity.GenerateNodeIdentity", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
RegisterOriginNode: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewIdentityRegisterOriginNode()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("Identity.RegisterOriginNode", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.RegisterOriginNode(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("Identity.RegisterOriginNode", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("Identity.RegisterOriginNode", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (h Identity) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(middlewares...)
|
||||
r.Post("/node/identity/generate", h.GenerateNodeIdentity)
|
||||
r.Post("/node/identity/register", h.RegisterOriginNode)
|
||||
})
|
||||
}
|
||||
132
federation/rest/handlers/node.go
Normal file
132
federation/rest/handlers/node.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package handlers
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
// Definitions file that controls how this file is generated:
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/pkg/logger"
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
NodeAPI interface {
|
||||
Create(context.Context, *request.NodeCreate) (interface{}, error)
|
||||
Pair(context.Context, *request.NodePair) (interface{}, error)
|
||||
HandshakeConfirm(context.Context, *request.NodeHandshakeConfirm) (interface{}, error)
|
||||
HandshakeComplete(context.Context, *request.NodeHandshakeComplete) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
Node struct {
|
||||
Create func(http.ResponseWriter, *http.Request)
|
||||
Pair func(http.ResponseWriter, *http.Request)
|
||||
HandshakeConfirm func(http.ResponseWriter, *http.Request)
|
||||
HandshakeComplete func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
)
|
||||
|
||||
func NewNode(h NodeAPI) *Node {
|
||||
return &Node{
|
||||
Create: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewNodeCreate()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("Node.Create", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.Create(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("Node.Create", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("Node.Create", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
Pair: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewNodePair()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("Node.Pair", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.Pair(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("Node.Pair", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("Node.Pair", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
HandshakeConfirm: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewNodeHandshakeConfirm()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("Node.HandshakeConfirm", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.HandshakeConfirm(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("Node.HandshakeConfirm", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("Node.HandshakeConfirm", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
HandshakeComplete: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewNodeHandshakeComplete()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("Node.HandshakeComplete", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.HandshakeComplete(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("Node.HandshakeComplete", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("Node.HandshakeComplete", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (h Node) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(middlewares...)
|
||||
r.Post("/nodes", h.Create)
|
||||
r.Post("/nodes/{nodeID}/pair", h.Pair)
|
||||
r.Post("/nodes/{nodeID}/handshake-confirm", h.HandshakeConfirm)
|
||||
r.Post("/nodes/{nodeID}/handshake-complete", h.HandshakeComplete)
|
||||
})
|
||||
}
|
||||
63
federation/rest/handlers/nodeHandshake.go
Normal file
63
federation/rest/handlers/nodeHandshake.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package handlers
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
// Definitions file that controls how this file is generated:
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/pkg/logger"
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
NodeHandshakeAPI interface {
|
||||
Initialize(context.Context, *request.NodeHandshakeInitialize) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
NodeHandshake struct {
|
||||
Initialize func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
)
|
||||
|
||||
func NewNodeHandshake(h NodeHandshakeAPI) *NodeHandshake {
|
||||
return &NodeHandshake{
|
||||
Initialize: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewNodeHandshakeInitialize()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("NodeHandshake.Initialize", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.Initialize(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("NodeHandshake.Initialize", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("NodeHandshake.Initialize", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (h NodeHandshake) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(middlewares...)
|
||||
r.Post("/nodes/{nodeID}/handshake", h.Initialize)
|
||||
})
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package handlers
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
// Definitions file that controls how this file is generated:
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/pkg/logger"
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
PairRequestAPI interface {
|
||||
RequestPairing(context.Context, *request.PairRequestRequestPairing) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
PairRequest struct {
|
||||
RequestPairing func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
)
|
||||
|
||||
func NewPairRequest(h PairRequestAPI) *PairRequest {
|
||||
return &PairRequest{
|
||||
RequestPairing: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewPairRequestRequestPairing()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("PairRequest.RequestPairing", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.RequestPairing(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("PairRequest.RequestPairing", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("PairRequest.RequestPairing", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (h PairRequest) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(middlewares...)
|
||||
r.Post("/node/pair/request/", h.RequestPairing)
|
||||
})
|
||||
}
|
||||
61
federation/rest/node.go
Normal file
61
federation/rest/node.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/federation/service"
|
||||
"github.com/cortezaproject/corteza-server/federation/types"
|
||||
)
|
||||
|
||||
type (
|
||||
Node struct {
|
||||
svcNode service.NodeService
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidNodeCreateParams = errors.New("create node: missing or invalid parameters")
|
||||
ErrorIdentityMissingToken = errors.New("identity: token missing")
|
||||
)
|
||||
|
||||
func (Node) New() *Node {
|
||||
return &Node{
|
||||
svcNode: service.DefaultNode,
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl Node) Create(ctx context.Context, r *request.NodeCreate) (interface{}, error) {
|
||||
if r.NodeURI == "" && (r.Domain == "" || r.Name == "") {
|
||||
return nil, ErrInvalidNodeCreateParams
|
||||
}
|
||||
|
||||
if r.NodeURI != "" {
|
||||
return ctrl.svcNode.CreateFromURI(ctx, r.NodeURI, r.MyDomain)
|
||||
} else if r.Domain != "" && r.Name != "" {
|
||||
n := &types.Node{}
|
||||
n.Domain = r.Domain
|
||||
n.Name = r.Name
|
||||
n.Status = types.NodeStatusPending
|
||||
|
||||
return ctrl.svcNode.Create(ctx, n, r.MyDomain)
|
||||
}
|
||||
|
||||
return nil, ErrInvalidNodeCreateParams
|
||||
}
|
||||
|
||||
func (ctrl Node) Pair(ctx context.Context, r *request.NodePair) (interface{}, error) {
|
||||
err := ctrl.svcNode.Pair(ctx, r.NodeID)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (ctrl Node) HandshakeConfirm(ctx context.Context, r *request.NodeHandshakeConfirm) (interface{}, error) {
|
||||
err := ctrl.svcNode.HandshakeConfirm(ctx, r.NodeID)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (ctrl Node) HandshakeComplete(ctx context.Context, r *request.NodeHandshakeComplete) (interface{}, error) {
|
||||
err := ctrl.svcNode.HandshakeComplete(ctx, r.NodeID, r.TokenA)
|
||||
return nil, err
|
||||
}
|
||||
25
federation/rest/node_handshake.go
Normal file
25
federation/rest/node_handshake.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/federation/service"
|
||||
)
|
||||
|
||||
type (
|
||||
NodeHandshake struct {
|
||||
svcNode service.NodeService
|
||||
}
|
||||
)
|
||||
|
||||
func (NodeHandshake) New() *NodeHandshake {
|
||||
return &NodeHandshake{
|
||||
svcNode: service.DefaultNode,
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl NodeHandshake) Initialize(ctx context.Context, r *request.NodeHandshakeInitialize) (interface{}, error) {
|
||||
err := ctrl.svcNode.HandshakeInit(ctx, r.NodeID, r.NodeIDB, r.NodeURI, r.TokenB)
|
||||
return nil, err
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
)
|
||||
|
||||
type (
|
||||
NodeIdentity struct{}
|
||||
)
|
||||
|
||||
func (NodeIdentity) New() *NodeIdentity {
|
||||
return &NodeIdentity{}
|
||||
}
|
||||
|
||||
func (ctrl NodeIdentity) GenerateNodeIdentity(ctx context.Context, r *request.IdentityGenerateNodeIdentity) (interface{}, error) {
|
||||
fmt.Println("GenerateNOdeIdentity")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (ctrl NodeIdentity) RegisterOriginNode(ctx context.Context, r *request.IdentityRegisterOriginNode) (interface{}, error) {
|
||||
fmt.Println("RegisterORiginNode")
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
)
|
||||
|
||||
type (
|
||||
NodePair struct{}
|
||||
)
|
||||
|
||||
func (NodePair) New() *NodePair {
|
||||
return &NodePair{}
|
||||
}
|
||||
|
||||
func (ctrl NodePair) ApprovePairing(ctx context.Context, r *request.PairApprovePairing) (interface{}, error) {
|
||||
fmt.Println("ApprovePairing")
|
||||
return nil, nil
|
||||
}
|
||||
func (ctrl NodePair) CompletePairing(ctx context.Context, r *request.PairCompletePairing) (interface{}, error) {
|
||||
fmt.Println("CompletePairing")
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
)
|
||||
|
||||
type (
|
||||
NodePairRequest struct{}
|
||||
)
|
||||
|
||||
func (NodePairRequest) New() *NodePairRequest {
|
||||
return &NodePairRequest{}
|
||||
}
|
||||
|
||||
func (ctrl NodePairRequest) RequestPairing(ctx context.Context, r *request.PairRequestRequestPairing) (interface{}, error) {
|
||||
fmt.Println("RequestPairing")
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
package request
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
// Definitions file that controls how this file is generated:
|
||||
//
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cortezaproject/corteza-server/pkg/payload"
|
||||
"github.com/go-chi/chi"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// dummy vars to prevent
|
||||
// unused imports complain
|
||||
var (
|
||||
_ = chi.URLParam
|
||||
_ = multipart.ErrMessageTooLarge
|
||||
_ = payload.ParseUint64s
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
IdentityGenerateNodeIdentity struct {
|
||||
// Domain POST parameter
|
||||
//
|
||||
// Domain of the destination node
|
||||
Domain string
|
||||
}
|
||||
|
||||
IdentityRegisterOriginNode struct {
|
||||
// Identifier POST parameter
|
||||
//
|
||||
// Origin node identifier
|
||||
Identifier string
|
||||
}
|
||||
)
|
||||
|
||||
// NewIdentityGenerateNodeIdentity request
|
||||
func NewIdentityGenerateNodeIdentity() *IdentityGenerateNodeIdentity {
|
||||
return &IdentityGenerateNodeIdentity{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r IdentityGenerateNodeIdentity) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"domain": r.Domain,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r IdentityGenerateNodeIdentity) GetDomain() string {
|
||||
return r.Domain
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *IdentityGenerateNodeIdentity) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if err = req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// POST params
|
||||
|
||||
if val, ok := req.Form["domain"]; ok && len(val) > 0 {
|
||||
r.Domain, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewIdentityRegisterOriginNode request
|
||||
func NewIdentityRegisterOriginNode() *IdentityRegisterOriginNode {
|
||||
return &IdentityRegisterOriginNode{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r IdentityRegisterOriginNode) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"identifier": r.Identifier,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r IdentityRegisterOriginNode) GetIdentifier() string {
|
||||
return r.Identifier
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *IdentityRegisterOriginNode) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if err = req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// POST params
|
||||
|
||||
if val, ok := req.Form["identifier"]; ok && len(val) > 0 {
|
||||
r.Identifier, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
340
federation/rest/request/node.go
Normal file
340
federation/rest/request/node.go
Normal file
@@ -0,0 +1,340 @@
|
||||
package request
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
// Definitions file that controls how this file is generated:
|
||||
//
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cortezaproject/corteza-server/pkg/payload"
|
||||
"github.com/go-chi/chi"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// dummy vars to prevent
|
||||
// unused imports complain
|
||||
var (
|
||||
_ = chi.URLParam
|
||||
_ = multipart.ErrMessageTooLarge
|
||||
_ = payload.ParseUint64s
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
NodeCreate struct {
|
||||
// MyDomain POST parameter
|
||||
//
|
||||
// [TMP] field that determines my domain
|
||||
MyDomain string
|
||||
|
||||
// Domain POST parameter
|
||||
//
|
||||
// Node B domain
|
||||
Domain string
|
||||
|
||||
// Name POST parameter
|
||||
//
|
||||
// Name for this node
|
||||
Name string
|
||||
|
||||
// AdminContact POST parameter
|
||||
//
|
||||
// Node B admin contact email
|
||||
AdminContact string
|
||||
|
||||
// NodeURI POST parameter
|
||||
//
|
||||
// Node A URI
|
||||
NodeURI string
|
||||
}
|
||||
|
||||
NodePair struct {
|
||||
// NodeID PATH parameter
|
||||
//
|
||||
// NodeID
|
||||
NodeID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
NodeHandshakeConfirm struct {
|
||||
// NodeID PATH parameter
|
||||
//
|
||||
// NodeID
|
||||
NodeID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
NodeHandshakeComplete struct {
|
||||
// NodeID PATH parameter
|
||||
//
|
||||
// NodeID
|
||||
NodeID uint64 `json:",string"`
|
||||
|
||||
// TokenA POST parameter
|
||||
//
|
||||
// Node A token
|
||||
TokenA string
|
||||
}
|
||||
)
|
||||
|
||||
// NewNodeCreate request
|
||||
func NewNodeCreate() *NodeCreate {
|
||||
return &NodeCreate{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeCreate) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"myDomain": r.MyDomain,
|
||||
"domain": r.Domain,
|
||||
"name": r.Name,
|
||||
"adminContact": r.AdminContact,
|
||||
"nodeURI": r.NodeURI,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeCreate) GetMyDomain() string {
|
||||
return r.MyDomain
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeCreate) GetDomain() string {
|
||||
return r.Domain
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeCreate) GetName() string {
|
||||
return r.Name
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeCreate) GetAdminContact() string {
|
||||
return r.AdminContact
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeCreate) GetNodeURI() string {
|
||||
return r.NodeURI
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *NodeCreate) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if err = req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// POST params
|
||||
|
||||
if val, ok := req.Form["myDomain"]; ok && len(val) > 0 {
|
||||
r.MyDomain, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if val, ok := req.Form["domain"]; ok && len(val) > 0 {
|
||||
r.Domain, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if val, ok := req.Form["name"]; ok && len(val) > 0 {
|
||||
r.Name, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if val, ok := req.Form["adminContact"]; ok && len(val) > 0 {
|
||||
r.AdminContact, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if val, ok := req.Form["nodeURI"]; ok && len(val) > 0 {
|
||||
r.NodeURI, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewNodePair request
|
||||
func NewNodePair() *NodePair {
|
||||
return &NodePair{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodePair) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"nodeID": r.NodeID,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodePair) GetNodeID() uint64 {
|
||||
return r.NodeID
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *NodePair) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "nodeID")
|
||||
r.NodeID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewNodeHandshakeConfirm request
|
||||
func NewNodeHandshakeConfirm() *NodeHandshakeConfirm {
|
||||
return &NodeHandshakeConfirm{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeHandshakeConfirm) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"nodeID": r.NodeID,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeHandshakeConfirm) GetNodeID() uint64 {
|
||||
return r.NodeID
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *NodeHandshakeConfirm) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "nodeID")
|
||||
r.NodeID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewNodeHandshakeComplete request
|
||||
func NewNodeHandshakeComplete() *NodeHandshakeComplete {
|
||||
return &NodeHandshakeComplete{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeHandshakeComplete) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"nodeID": r.NodeID,
|
||||
"tokenA": r.TokenA,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeHandshakeComplete) GetNodeID() uint64 {
|
||||
return r.NodeID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeHandshakeComplete) GetTokenA() string {
|
||||
return r.TokenA
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *NodeHandshakeComplete) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if err = req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// POST params
|
||||
|
||||
if val, ok := req.Form["tokenA"]; ok && len(val) > 0 {
|
||||
r.TokenA, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "nodeID")
|
||||
r.NodeID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
145
federation/rest/request/nodeHandshake.go
Normal file
145
federation/rest/request/nodeHandshake.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package request
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
// Definitions file that controls how this file is generated:
|
||||
//
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cortezaproject/corteza-server/pkg/payload"
|
||||
"github.com/go-chi/chi"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// dummy vars to prevent
|
||||
// unused imports complain
|
||||
var (
|
||||
_ = chi.URLParam
|
||||
_ = multipart.ErrMessageTooLarge
|
||||
_ = payload.ParseUint64s
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
NodeHandshakeInitialize struct {
|
||||
// NodeID PATH parameter
|
||||
//
|
||||
// NodeID
|
||||
NodeID uint64 `json:",string"`
|
||||
|
||||
// NodeURI POST parameter
|
||||
//
|
||||
// Node A node URI
|
||||
NodeURI string
|
||||
|
||||
// TokenB POST parameter
|
||||
//
|
||||
// Node B auth token
|
||||
TokenB string
|
||||
|
||||
// NodeIDB POST parameter
|
||||
//
|
||||
// Node B nodeID
|
||||
NodeIDB uint64 `json:",string"`
|
||||
}
|
||||
)
|
||||
|
||||
// NewNodeHandshakeInitialize request
|
||||
func NewNodeHandshakeInitialize() *NodeHandshakeInitialize {
|
||||
return &NodeHandshakeInitialize{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeHandshakeInitialize) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"nodeID": r.NodeID,
|
||||
"nodeURI": r.NodeURI,
|
||||
"tokenB": r.TokenB,
|
||||
"nodeIDB": r.NodeIDB,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeHandshakeInitialize) GetNodeID() uint64 {
|
||||
return r.NodeID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeHandshakeInitialize) GetNodeURI() string {
|
||||
return r.NodeURI
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeHandshakeInitialize) GetTokenB() string {
|
||||
return r.TokenB
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r NodeHandshakeInitialize) GetNodeIDB() uint64 {
|
||||
return r.NodeIDB
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *NodeHandshakeInitialize) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if err = req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// POST params
|
||||
|
||||
if val, ok := req.Form["nodeURI"]; ok && len(val) > 0 {
|
||||
r.NodeURI, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if val, ok := req.Form["tokenB"]; ok && len(val) > 0 {
|
||||
r.TokenB, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if val, ok := req.Form["nodeIDB"]; ok && len(val) > 0 {
|
||||
r.NodeIDB, err = payload.ParseUint64(val[0]), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "nodeID")
|
||||
r.NodeID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package request
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
// Definitions file that controls how this file is generated:
|
||||
//
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cortezaproject/corteza-server/pkg/payload"
|
||||
"github.com/go-chi/chi"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// dummy vars to prevent
|
||||
// unused imports complain
|
||||
var (
|
||||
_ = chi.URLParam
|
||||
_ = multipart.ErrMessageTooLarge
|
||||
_ = payload.ParseUint64s
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
PairRequestRequestPairing struct {
|
||||
// Identifier POST parameter
|
||||
//
|
||||
// Origin node identifier
|
||||
Identifier string
|
||||
|
||||
// Token POST parameter
|
||||
//
|
||||
// Destination node token
|
||||
Token string
|
||||
}
|
||||
)
|
||||
|
||||
// NewPairRequestRequestPairing request
|
||||
func NewPairRequestRequestPairing() *PairRequestRequestPairing {
|
||||
return &PairRequestRequestPairing{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r PairRequestRequestPairing) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"identifier": r.Identifier,
|
||||
"token": r.Token,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r PairRequestRequestPairing) GetIdentifier() string {
|
||||
return r.Identifier
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r PairRequestRequestPairing) GetToken() string {
|
||||
return r.Token
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *PairRequestRequestPairing) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if err = req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// POST params
|
||||
|
||||
if val, ok := req.Form["identifier"]; ok && len(val) > 0 {
|
||||
r.Identifier, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if val, ok := req.Form["token"]; ok && len(val) > 0 {
|
||||
r.Token, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
func MountRoutes(r chi.Router) {
|
||||
r.Group(func(r chi.Router) {
|
||||
handlers.NewPairRequest(NodePairRequest{}.New()).MountRoutes(r)
|
||||
handlers.NewNodeHandshake(NodeHandshake{}.New()).MountRoutes(r)
|
||||
|
||||
// temporary because of acl
|
||||
handlers.NewManageStructure((ManageStructure{}.New())).MountRoutes(r)
|
||||
@@ -20,7 +20,6 @@ func MountRoutes(r chi.Router) {
|
||||
r.Use(auth.MiddlewareValidOnly)
|
||||
r.Use(middlewareAllowedAccess)
|
||||
|
||||
handlers.NewIdentity(NodeIdentity{}.New()).MountRoutes(r)
|
||||
handlers.NewPair(NodePair{}.New()).MountRoutes(r)
|
||||
handlers.NewNode(Node{}.New()).MountRoutes(r)
|
||||
})
|
||||
}
|
||||
|
||||
214
federation/service/node.go
Normal file
214
federation/service/node.go
Normal file
@@ -0,0 +1,214 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/types"
|
||||
"github.com/cortezaproject/corteza-server/federation/util"
|
||||
"github.com/cortezaproject/corteza-server/pkg/actionlog"
|
||||
"github.com/cortezaproject/corteza-server/pkg/auth"
|
||||
"github.com/cortezaproject/corteza-server/pkg/id"
|
||||
"github.com/cortezaproject/corteza-server/pkg/rand"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
"github.com/cortezaproject/corteza-server/system/service"
|
||||
stypes "github.com/cortezaproject/corteza-server/system/types"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
var (
|
||||
// This is temporary for local testing
|
||||
tmpNodeStore = make(types.NodeSet, 0)
|
||||
|
||||
ErrorNodeNotFound = errors.New("pair: node not found")
|
||||
ErrorInvalidNodeURI = errors.New("pair: invalid node uri provided")
|
||||
)
|
||||
|
||||
const (
|
||||
TokenLength = 15
|
||||
)
|
||||
|
||||
type (
|
||||
node struct {
|
||||
store store.Storer
|
||||
sysUser service.UserService
|
||||
|
||||
actionlog actionlog.Recorder
|
||||
|
||||
tokenEncoder auth.TokenEncoder
|
||||
}
|
||||
|
||||
NodeService interface {
|
||||
Create(ctx context.Context, n *types.Node, sharedDomain string) (*types.Node, error)
|
||||
CreateFromURI(ctx context.Context, uri string, sharedDomain string) (*types.Node, error)
|
||||
|
||||
Pair(ctx context.Context, nodeID uint64) error
|
||||
HandshakeInit(ctx context.Context, sourceNodeID, nodeIDB uint64, nodeURI, token string) error
|
||||
HandshakeConfirm(ctx context.Context, nodeID uint64) error
|
||||
HandshakeComplete(ctx context.Context, nodeID uint64, token string) error
|
||||
}
|
||||
)
|
||||
|
||||
func Node(s store.Storer, u service.UserService, al actionlog.Recorder, th auth.TokenHandler) NodeService {
|
||||
return (&node{
|
||||
store: s,
|
||||
sysUser: u,
|
||||
actionlog: al,
|
||||
tokenEncoder: th,
|
||||
})
|
||||
}
|
||||
|
||||
// @todo move myDomain to configuration
|
||||
func (svc node) Create(ctx context.Context, n *types.Node, myDomain string) (*types.Node, error) {
|
||||
n.ID = id.Next()
|
||||
n.Status = types.NodeStatusPending
|
||||
|
||||
ott := string(rand.Bytes(TokenLength))
|
||||
i := util.EncodeURI(ott, myDomain, n.ID)
|
||||
if n.NodeURI == "" {
|
||||
n.NodeURI = i
|
||||
}
|
||||
|
||||
// @todo store an initial Node entry
|
||||
tmpNodeStore = append(tmpNodeStore, n)
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (svc node) CreateFromURI(ctx context.Context, uri string, sharedDomain string) (*types.Node, error) {
|
||||
n := &types.Node{
|
||||
ID: id.Next(),
|
||||
Status: types.NodeStatusPending,
|
||||
}
|
||||
|
||||
uri, err := url.QueryUnescape(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pr, err := util.DecodeURI(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n.Domain = pr.Domain
|
||||
n.Name = pr.Params.Name
|
||||
n.Status = types.NodeStatusPending
|
||||
n.NodeURI = uri
|
||||
|
||||
// @todo store an initial Node entry
|
||||
tmpNodeStore = append(tmpNodeStore, n)
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (svc node) Pair(ctx context.Context, nodeID uint64) error {
|
||||
// @todo store
|
||||
n := tmpNodeStore.FindByID(nodeID)
|
||||
if n == nil {
|
||||
return ErrorNodeNotFound
|
||||
}
|
||||
|
||||
// Handle fenedrated user
|
||||
u, err := svc.fetchFederatedUser(ctx, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate JWT token for the federated user
|
||||
t := svc.tokenEncoder.Encode(u)
|
||||
// @todo remove
|
||||
spew.Dump(u, t)
|
||||
|
||||
// Ping node A to request the handshake
|
||||
// @todo...
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc node) HandshakeInit(ctx context.Context, nodeIDA, nodeIDB uint64, nodeURI, token string) error {
|
||||
// @todo store
|
||||
n := tmpNodeStore.FindByID(nodeIDA)
|
||||
if n == nil {
|
||||
return ErrorNodeNotFound
|
||||
}
|
||||
|
||||
if n.NodeURI != nodeURI {
|
||||
return ErrorInvalidNodeURI
|
||||
}
|
||||
|
||||
// @todo store...
|
||||
n.Token = token
|
||||
n.SharedID = nodeIDA
|
||||
n.Status = types.NodeStatusPairRequest
|
||||
spew.Dump(n)
|
||||
|
||||
// Notify the node administrator about the request
|
||||
// @todo
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc node) HandshakeConfirm(ctx context.Context, nodeID uint64) error {
|
||||
// @todo store
|
||||
n := tmpNodeStore.FindByID(nodeID)
|
||||
if n == nil {
|
||||
return ErrorNodeNotFound
|
||||
}
|
||||
|
||||
// Handle fenedrated user
|
||||
u, err := svc.fetchFederatedUser(ctx, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate JWT token for the federated user
|
||||
t := svc.tokenEncoder.Encode(u)
|
||||
// @todo remove
|
||||
spew.Dump(u, t)
|
||||
|
||||
// Ping node B to complete the handshake
|
||||
// @todo...
|
||||
|
||||
// @todo store
|
||||
n.Status = types.NodeStatusPairComplete
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc node) HandshakeComplete(ctx context.Context, nodeID uint64, token string) error {
|
||||
// @todo store
|
||||
n := tmpNodeStore.FindByID(nodeID)
|
||||
if n == nil {
|
||||
return ErrorNodeNotFound
|
||||
}
|
||||
|
||||
// Final update -- update the token and node status
|
||||
// @todo store
|
||||
n.Token = token
|
||||
n.Status = types.NodeStatusPairComplete
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc node) fetchFederatedUser(ctx context.Context, n *types.Node) (*stypes.User, error) {
|
||||
// Handle fenedrated user
|
||||
uHandle := "federation_" + strconv.FormatUint(n.ID, 10)
|
||||
u, _ := svc.sysUser.With(ctx).FindByHandle(uHandle)
|
||||
|
||||
if u == nil {
|
||||
var err error
|
||||
|
||||
// Create a system user to service this node
|
||||
u, err = svc.sysUser.With(ctx).Create(&stypes.User{
|
||||
Email: strconv.FormatUint(n.ID, 10) + "@federation.corteza",
|
||||
Handle: uHandle,
|
||||
Kind: stypes.FederationUser,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/actionlog"
|
||||
"github.com/cortezaproject/corteza-server/pkg/auth"
|
||||
"github.com/cortezaproject/corteza-server/pkg/healthcheck"
|
||||
"github.com/cortezaproject/corteza-server/pkg/id"
|
||||
"github.com/cortezaproject/corteza-server/pkg/objstore"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"github.com/cortezaproject/corteza-server/pkg/objstore/plain"
|
||||
"github.com/cortezaproject/corteza-server/pkg/options"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
"github.com/cortezaproject/corteza-server/system/service"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -38,6 +40,8 @@ var (
|
||||
|
||||
DefaultActionlog actionlog.Recorder
|
||||
|
||||
DefaultNode NodeService
|
||||
|
||||
// wrapper around time.Now() that will aid service testing
|
||||
now = func() *time.Time {
|
||||
c := time.Now()
|
||||
@@ -112,5 +116,7 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, c Config)
|
||||
|
||||
hcd.Add(objstore.Healthcheck(DefaultObjectStore), "Store/Federation")
|
||||
|
||||
DefaultNode = Node(DefaultStore, service.DefaultUser, DefaultActionlog, auth.DefaultJwtHandler)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
package types
|
||||
|
||||
var (
|
||||
NodeStatusPending = "pending"
|
||||
NodeStatusPairRequest = "pair_requested"
|
||||
NodeStatusPairComplete = "paired"
|
||||
)
|
||||
|
||||
type (
|
||||
Node struct {
|
||||
ID uint64 `json:"recordID,string"`
|
||||
Name string `json:"name,string"`
|
||||
ID uint64 `json:"nodeID,string"`
|
||||
SharedID uint64 `json:"sharedNodeID,string"`
|
||||
Name string `json:"name,string"`
|
||||
Domain string `json:"domain,string"`
|
||||
Status string `json:"status,string"`
|
||||
Token string `json:"-"`
|
||||
NodeURI string `json:"nodeURI,string"`
|
||||
}
|
||||
)
|
||||
|
||||
71
federation/util/util.go
Normal file
71
federation/util/util.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorURIMissingToken = errors.New("uri: token missing")
|
||||
)
|
||||
|
||||
const ()
|
||||
|
||||
type (
|
||||
NodeURIParams struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
DecodedURI struct {
|
||||
Domain string
|
||||
Token string
|
||||
NodeID uint64
|
||||
Params NodeURIParams
|
||||
}
|
||||
)
|
||||
|
||||
func DecodeURI(i string) (du *DecodedURI, err error) {
|
||||
du = &DecodedURI{
|
||||
Params: NodeURIParams{},
|
||||
}
|
||||
|
||||
u, err := url.Parse(i)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
du.Domain = u.Host
|
||||
nodeS := u.User.Username()
|
||||
if nodeS == "" {
|
||||
return nil, ErrorURIMissingToken
|
||||
}
|
||||
nodeID, err := strconv.ParseUint(nodeS, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
du.NodeID = nodeID
|
||||
|
||||
token, has := u.User.Password()
|
||||
if !has {
|
||||
return nil, ErrorURIMissingToken
|
||||
}
|
||||
du.Token = token
|
||||
|
||||
params := u.Query()
|
||||
if name, has := params["name"]; has && len(name) > 0 {
|
||||
du.Params.Name = name[0]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func EncodeURI(ott, domain string, nodeID uint64) string {
|
||||
u := url.URL{
|
||||
Scheme: "corteza",
|
||||
User: url.UserPassword(strconv.FormatUint(nodeID, 10), ott),
|
||||
Host: domain,
|
||||
}
|
||||
|
||||
return u.String()
|
||||
}
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cortezaproject/corteza-server/pkg/filter"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/filter"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/rbac"
|
||||
@@ -83,8 +84,9 @@ type (
|
||||
)
|
||||
|
||||
const (
|
||||
NormalUser UserKind = ""
|
||||
BotUser UserKind = "bot"
|
||||
NormalUser UserKind = ""
|
||||
BotUser UserKind = "bot"
|
||||
FederationUser UserKind = "fdr"
|
||||
)
|
||||
|
||||
func (u User) String() string {
|
||||
|
||||
Reference in New Issue
Block a user