Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discovery: SQLite-based server implementation #2589

Merged
merged 24 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,9 @@ The following options can be configured on the server:
:widths: 20 30 50
:class: options-table

==================================== =============================================================================================================================================================================================================================================================================================================== ==================================================================================================================================================================================================================================
==================================== =============================================================================================================================================================================================================================================================================================================== ================================================================================================================================================================================================================================================
Key Default Description
==================================== =============================================================================================================================================================================================================================================================================================================== ==================================================================================================================================================================================================================================
==================================== =============================================================================================================================================================================================================================================================================================================== ================================================================================================================================================================================================================================================
configfile nuts.yaml Nuts config file
cpuprofile When set, a CPU profile is written to the given path. Ignored when strictmode is set.
datadir ./data Directory where the node stores its files.
Expand Down Expand Up @@ -224,7 +224,7 @@ The following options can be configured on the server:
http.default.auth.type Whether to enable authentication for the default interface, specify 'token_v2' for bearer token mode or 'token' for legacy bearer token mode.
http.default.cors.origin [] When set, enables CORS from the specified origins on the default HTTP interface.
**JSONLD**
jsonld.contexts.localmapping [https://w3c-ccg.github.io/lds-jws2020/contexts/lds-jws2020-v1.json=assets/contexts/lds-jws2020-v1.ldjson,https://schema.org=assets/contexts/schema-org-v13.ldjson,https://nuts.nl/credentials/v1=assets/contexts/nuts.ldjson,https://www.w3.org/2018/credentials/v1=assets/contexts/w3c-credentials-v1.ldjson] This setting allows mapping external URLs to local files for e.g. preventing external dependencies. These mappings have precedence over those in remoteallowlist.
jsonld.contexts.localmapping [https://nuts.nl/credentials/v1=assets/contexts/nuts.ldjson,https://www.w3.org/2018/credentials/v1=assets/contexts/w3c-credentials-v1.ldjson,https://w3c-ccg.github.io/lds-jws2020/contexts/lds-jws2020-v1.json=assets/contexts/lds-jws2020-v1.ldjson,https://schema.org=assets/contexts/schema-org-v13.ldjson] This setting allows mapping external URLs to local files for e.g. preventing external dependencies. These mappings have precedence over those in remoteallowlist.
jsonld.contexts.remoteallowlist [https://schema.org,https://www.w3.org/2018/credentials/v1,https://w3c-ccg.github.io/lds-jws2020/contexts/lds-jws2020-v1.json] In strict mode, fetching external JSON-LD contexts is not allowed except for context-URLs listed here.
**Network**
network.bootstrapnodes [] List of bootstrap nodes ('<host>:<port>') which the node initially connect to.
Expand Down Expand Up @@ -252,12 +252,12 @@ The following options can be configured on the server:
storage.redis.sentinel.password Password for authenticating to Redis Sentinels.
storage.redis.sentinel.username Username for authenticating to Redis Sentinels.
storage.redis.tls.truststorefile PEM file containing the trusted CA certificate(s) for authenticating remote Redis servers. Can only be used when connecting over TLS (use 'rediss://' as scheme in address).
storage.sql.connection Connection string for the SQL database. If not set, it defaults to a SQLite database stored inside the configured data directory
storage.sql.connection Connection string for the SQL database. If not set, it defaults to a SQLite database stored inside the configured data directory. If specifying a SQLite database, make sure to enable foreign keys with the '_foreign_keys=on' query parameter.
reinkrul marked this conversation as resolved.
Show resolved Hide resolved
**VCR**
vcr.openid4vci.definitionsdir Directory with the additional credential definitions the node could issue (experimental, may change without notice).
vcr.openid4vci.enabled true Enable issuing and receiving credentials over OpenID4VCI.
vcr.openid4vci.timeout 30s Time-out for OpenID4VCI HTTP client operations.
==================================== =============================================================================================================================================================================================================================================================================================================== ==================================================================================================================================================================================================================================
==================================== =============================================================================================================================================================================================================================================================================================================== ================================================================================================================================================================================================================================================

This table is automatically generated using the configuration flags in the core and engines. When they're changed
the options table must be regenerated using the Makefile:
Expand Down
29 changes: 29 additions & 0 deletions discoveryservice/api/v1/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 Nuts community
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

package v1
reinkrul marked this conversation as resolved.
Show resolved Hide resolved

//// lists maps a list name (last path part of use case endpoint) to the list ID
//lists map[string]string
//// name is derived from endpoint: it's the last path part of the definition endpoint
//// It is used to route HTTP GET requests to the correct list.
//pathParts := strings.Split(definition.Endpoint, "/")
//name := pathParts[len(pathParts)-1]
//if name == "" {
//return nil, fmt.Errorf("can't derive list name from definition endpoint: %s", definition.Endpoint)
//}
50 changes: 50 additions & 0 deletions discoveryservice/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2023 Nuts community
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

package discoveryservice
reinkrul marked this conversation as resolved.
Show resolved Hide resolved

// Config holds the config of the module
type Config struct {
Server ServerConfig `koanf:"server"`
Definitions DefinitionsConfig `koanf:"definitions"`
}

// DefinitionsConfig holds the config for loading Service Definitions.
type DefinitionsConfig struct {
Directory string `koanf:"directory"`
}

// ServerConfig holds the config for the server
type ServerConfig struct {
// DefinitionIDs specifies which use case lists the server serves.
DefinitionIDs []string `koanf:"definition_ids"`
// Directory is the directory where the server stores the lists.
Directory string `koanf:"directory"`
reinkrul marked this conversation as resolved.
Show resolved Hide resolved
}

// DefaultConfig returns the default configuration.
func DefaultConfig() Config {
return Config{
Server: ServerConfig{},
}
}

// IsServer returns true if the node act as Discovery Server.
func (c Config) IsServer() bool {
return len(c.Server.DefinitionIDs) > 0
}
68 changes: 68 additions & 0 deletions discoveryservice/definition.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2023 Nuts community
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

package discoveryservice

import (
"bytes"
"embed"
"encoding/json"
"github.com/nuts-foundation/nuts-node/vcr/pe"
v2 "github.com/nuts-foundation/nuts-node/vcr/pe/schema/v2"
"github.com/santhosh-tekuri/jsonschema"
)

//go:embed *.json
var jsonSchemaFiles embed.FS
var definitionJsonSchema *jsonschema.Schema

func init() {
serviceDefinitionSchemaData, err := jsonSchemaFiles.ReadFile("service-definition-schema.json")
if err != nil {
panic(err)
reinkrul marked this conversation as resolved.
Show resolved Hide resolved
}
const schemaURL = "http://nuts.nl/schemas/discovery-service-v0.json"
if err := v2.Compiler.AddResource(schemaURL, bytes.NewReader(serviceDefinitionSchemaData)); err != nil {
panic(err)
}
definitionJsonSchema = v2.Compiler.MustCompile(schemaURL)
}

// Definition holds the definition of a service.
type Definition struct {
// ID is the unique identifier of the use case.
ID string `json:"id"`
// Endpoint is the endpoint where the use case list is served.
Endpoint string `json:"endpoint"`
// PresentationDefinition specifies the Presentation Definition submissions to the list must conform to,
// according to the Presentation Exchange specification.
PresentationDefinition pe.PresentationDefinition `json:"presentation_definition"`
// PresentationMaxValidity specifies how long submitted presentations are allowed to be valid (in seconds).
PresentationMaxValidity int `json:"presentation_max_validity"`
}

func ParseDefinition(data []byte) (*Definition, error) {
if err := definitionJsonSchema.Validate(bytes.NewReader(data)); err != nil {
return nil, err
}
var definition Definition
if err := json.Unmarshal(data, &definition); err != nil {
return nil, err
}
return &definition, nil
}
42 changes: 42 additions & 0 deletions discoveryservice/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2023 Nuts community
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

package discoveryservice

import (
"github.com/nuts-foundation/go-did/vc"
)

// Timestamp is value that references a point in the list.
// It is used by clients to request new entries since their last query.
// It's implemented as lamport timestamp (https://en.wikipedia.org/wiki/Lamport_timestamp);
// it is incremented when a new entry is added to the list.
// Pass 0 to start at the beginning of the list.
type Timestamp uint64

type Server interface {
reinkrul marked this conversation as resolved.
Show resolved Hide resolved
// Add registers a presentation of the given Discovery Service.
// If the presentation is not valid or it does not conform to the Service Definition, it returns an error.
Add(serviceID string, presentation vc.VerifiablePresentation) error
// Get retrieves the presentations for the given service, starting at the given timestamp.
Get(serviceID string, startAt Timestamp) ([]vc.VerifiablePresentation, *Timestamp, error)
}

type Client interface {
Search(serviceID string, query map[string]string) ([]vc.VerifiablePresentation, error)
}
31 changes: 31 additions & 0 deletions discoveryservice/log/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2023 Nuts community
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

package log

import (
"github.com/nuts-foundation/nuts-node/core"
"github.com/sirupsen/logrus"
)

var _logger = logrus.StandardLogger().WithField(core.LogFieldModule, "DiscoveryService")

// Logger returns a logger with the module field set
func Logger() *logrus.Entry {
return _logger
}
Loading
Loading