wip: migrate to mono-repo. SPN has already been moved to spn/
This commit is contained in:
244
spn/access/token/request.go
Normal file
244
spn/access/token/request.go
Normal file
@@ -0,0 +1,244 @@
|
||||
package token
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/mr-tron/base58"
|
||||
)
|
||||
|
||||
const sessionIDSize = 32
|
||||
|
||||
// RequestHandlingState is a request handling state.
|
||||
type RequestHandlingState struct {
|
||||
SessionID string
|
||||
PBlind map[string]*PBlindSignerState
|
||||
}
|
||||
|
||||
// SetupRequest is a setup request.
|
||||
type SetupRequest struct {
|
||||
PBlind map[string]struct{} `json:"PB,omitempty"`
|
||||
}
|
||||
|
||||
// SetupResponse is a setup response.
|
||||
type SetupResponse struct {
|
||||
SessionID string `json:"ID,omitempty"`
|
||||
PBlind map[string]*PBlindSetupResponse `json:"PB,omitempty"`
|
||||
}
|
||||
|
||||
// TokenRequest is a token request.
|
||||
type TokenRequest struct { //nolint:golint // Be explicit.
|
||||
SessionID string `json:"ID,omitempty"`
|
||||
PBlind map[string]*PBlindTokenRequest `json:"PB,omitempty"`
|
||||
Scramble map[string]*ScrambleTokenRequest `json:"S,omitempty"`
|
||||
}
|
||||
|
||||
// IssuedTokens are issued tokens.
|
||||
type IssuedTokens struct {
|
||||
PBlind map[string]*IssuedPBlindTokens `json:"PB,omitempty"`
|
||||
Scramble map[string]*IssuedScrambleTokens `json:"SC,omitempty"`
|
||||
}
|
||||
|
||||
// CreateSetupRequest creates a combined setup request for all registered tokens, if needed.
|
||||
func CreateSetupRequest() (request *SetupRequest, setupRequired bool) {
|
||||
registryLock.RLock()
|
||||
defer registryLock.RUnlock()
|
||||
|
||||
request = &SetupRequest{
|
||||
PBlind: make(map[string]struct{}, len(pblindRegistry)),
|
||||
}
|
||||
|
||||
// Go through handlers and create request setups.
|
||||
for _, pblindHandler := range pblindRegistry {
|
||||
// Check if we need to request with this handler.
|
||||
if pblindHandler.ShouldRequest() {
|
||||
request.PBlind[pblindHandler.Zone()] = struct{}{}
|
||||
setupRequired = true
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// HandleSetupRequest handles a setup request for all registered tokens.
|
||||
func HandleSetupRequest(request *SetupRequest) (*RequestHandlingState, *SetupResponse, error) {
|
||||
registryLock.RLock()
|
||||
defer registryLock.RUnlock()
|
||||
|
||||
// Generate session token.
|
||||
randomID := make([]byte, sessionIDSize)
|
||||
n, err := rand.Read(randomID)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to generate session ID: %w", err)
|
||||
}
|
||||
if n != sessionIDSize {
|
||||
return nil, nil, fmt.Errorf("failed to get full session ID: only got %d bytes", n)
|
||||
}
|
||||
sessionID := base58.Encode(randomID)
|
||||
|
||||
// Create state and response.
|
||||
state := &RequestHandlingState{
|
||||
SessionID: sessionID,
|
||||
PBlind: make(map[string]*PBlindSignerState, len(pblindRegistry)),
|
||||
}
|
||||
setup := &SetupResponse{
|
||||
SessionID: sessionID,
|
||||
PBlind: make(map[string]*PBlindSetupResponse, len(pblindRegistry)),
|
||||
}
|
||||
|
||||
// Go through handlers and create setups.
|
||||
for _, pblindHandler := range pblindRegistry {
|
||||
// Check if we have a request for this handler.
|
||||
_, ok := request.PBlind[pblindHandler.Zone()]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
plindState, pblindSetup, err := pblindHandler.CreateSetup()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create setup for %s: %w", pblindHandler.Zone(), err)
|
||||
}
|
||||
|
||||
state.PBlind[pblindHandler.Zone()] = plindState
|
||||
setup.PBlind[pblindHandler.Zone()] = pblindSetup
|
||||
}
|
||||
|
||||
return state, setup, nil
|
||||
}
|
||||
|
||||
// CreateTokenRequest creates a token request for all registered tokens.
|
||||
func CreateTokenRequest(setup *SetupResponse) (request *TokenRequest, requestRequired bool, err error) {
|
||||
registryLock.RLock()
|
||||
defer registryLock.RUnlock()
|
||||
|
||||
// Check setup data.
|
||||
if setup != nil && setup.SessionID == "" {
|
||||
return nil, false, errors.New("setup data is missing a session ID")
|
||||
}
|
||||
|
||||
// Create token request.
|
||||
request = &TokenRequest{
|
||||
PBlind: make(map[string]*PBlindTokenRequest, len(pblindRegistry)),
|
||||
Scramble: make(map[string]*ScrambleTokenRequest, len(scrambleRegistry)),
|
||||
}
|
||||
if setup != nil {
|
||||
request.SessionID = setup.SessionID
|
||||
}
|
||||
|
||||
// Go through handlers and create requests.
|
||||
if setup != nil {
|
||||
for _, pblindHandler := range pblindRegistry {
|
||||
// Check if we have setup data for this handler.
|
||||
pblindSetup, ok := setup.PBlind[pblindHandler.Zone()]
|
||||
if !ok {
|
||||
// TODO: Abort if we should have received request data.
|
||||
continue
|
||||
}
|
||||
|
||||
// Create request.
|
||||
pblindRequest, err := pblindHandler.CreateTokenRequest(pblindSetup)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("failed to create token request for %s: %w", pblindHandler.Zone(), err)
|
||||
}
|
||||
|
||||
requestRequired = true
|
||||
request.PBlind[pblindHandler.Zone()] = pblindRequest
|
||||
}
|
||||
}
|
||||
for _, scrambleHandler := range scrambleRegistry {
|
||||
// Check if we need to request with this handler.
|
||||
if scrambleHandler.ShouldRequest() {
|
||||
requestRequired = true
|
||||
request.Scramble[scrambleHandler.Zone()] = scrambleHandler.CreateTokenRequest()
|
||||
}
|
||||
}
|
||||
|
||||
return request, requestRequired, nil
|
||||
}
|
||||
|
||||
// IssueTokens issues tokens for all registered tokens.
|
||||
func IssueTokens(state *RequestHandlingState, request *TokenRequest) (response *IssuedTokens, err error) {
|
||||
registryLock.RLock()
|
||||
defer registryLock.RUnlock()
|
||||
|
||||
// Create token response.
|
||||
response = &IssuedTokens{
|
||||
PBlind: make(map[string]*IssuedPBlindTokens, len(pblindRegistry)),
|
||||
Scramble: make(map[string]*IssuedScrambleTokens, len(scrambleRegistry)),
|
||||
}
|
||||
|
||||
// Go through handlers and create requests.
|
||||
for _, pblindHandler := range pblindRegistry {
|
||||
// Check if we have all the data for issuing.
|
||||
pblindState, ok := state.PBlind[pblindHandler.Zone()]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
pblindRequest, ok := request.PBlind[pblindHandler.Zone()]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Issue tokens.
|
||||
pblindTokens, err := pblindHandler.IssueTokens(pblindState, pblindRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to issue tokens for %s: %w", pblindHandler.Zone(), err)
|
||||
}
|
||||
|
||||
response.PBlind[pblindHandler.Zone()] = pblindTokens
|
||||
}
|
||||
for _, scrambleHandler := range scrambleRegistry {
|
||||
// Check if we have all the data for issuing.
|
||||
scrambleRequest, ok := request.Scramble[scrambleHandler.Zone()]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Issue tokens.
|
||||
scrambleTokens, err := scrambleHandler.IssueTokens(scrambleRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to issue tokens for %s: %w", scrambleHandler.Zone(), err)
|
||||
}
|
||||
|
||||
response.Scramble[scrambleHandler.Zone()] = scrambleTokens
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ProcessIssuedTokens processes issued tokens for all registered tokens.
|
||||
func ProcessIssuedTokens(response *IssuedTokens) error {
|
||||
registryLock.RLock()
|
||||
defer registryLock.RUnlock()
|
||||
|
||||
// Go through handlers and create requests.
|
||||
for _, pblindHandler := range pblindRegistry {
|
||||
// Check if we received tokens.
|
||||
pblindResponse, ok := response.PBlind[pblindHandler.Zone()]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Process issued tokens.
|
||||
err := pblindHandler.ProcessIssuedTokens(pblindResponse)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to process issued tokens for %s: %w", pblindHandler.Zone(), err)
|
||||
}
|
||||
}
|
||||
for _, scrambleHandler := range scrambleRegistry {
|
||||
// Check if we received tokens.
|
||||
scrambleResponse, ok := response.Scramble[scrambleHandler.Zone()]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Process issued tokens.
|
||||
err := scrambleHandler.ProcessIssuedTokens(scrambleResponse)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to process issued tokens for %s: %w", scrambleHandler.Zone(), err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user