feature/1121 implement ucan validation (#1176)

- **refactor: remove unused auth components**
- **refactor: improve devbox configuration and deployment process**
- **refactor: improve devnet and testnet setup**
- **fix: update templ version to v0.2.778**
- **refactor: rename pkl/net.matrix to pkl/matrix.net**
- **refactor: migrate webapp components to nebula**
- **refactor: protobuf types**
- **chore: update dependencies for improved security and stability**
- **feat: implement landing page and vault gateway servers**
- **refactor: Migrate data models to new module structure and update
related files**
- **feature/1121-implement-ucan-validation**
- **refactor: Replace hardcoded constants with model types in attns.go**
- **feature/1121-implement-ucan-validation**
- **chore: add origin Host struct and update main function to handle
multiple hosts**
- **build: remove unused static files from dwn module**
- **build: remove unused static files from dwn module**
- **refactor: Move DWN models to common package**
- **refactor: move models to pkg/common**
- **refactor: move vault web app assets to embed module**
- **refactor: update session middleware import path**
- **chore: configure port labels and auto-forwarding behavior**
- **feat: enhance devcontainer configuration**
- **feat: Add UCAN middleware for Echo with flexible token validation**
- **feat: add JWT middleware for UCAN authentication**
- **refactor: update package URI and versioning in PklProject files**
- **fix: correct sonr.pkl import path**
- **refactor: move JWT related code to auth package**
- **feat: introduce vault configuration retrieval and management**
- **refactor: Move vault components to gateway module and update file
paths**
- **refactor: remove Dexie and SQLite database implementations**
- **feat: enhance frontend with PWA features and WASM integration**
- **feat: add Devbox features and streamline Dockerfile**
- **chore: update dependencies to include TigerBeetle**
- **chore(deps): update go version to 1.23**
- **feat: enhance devnet setup with PATH environment variable and
updated PWA manifest**
- **fix: upgrade tigerbeetle-go dependency and remove indirect
dependency**
- **feat: add PostgreSQL support to devnet and testnet deployments**
- **refactor: rename keyshare cookie to token cookie**
- **feat: upgrade Go version to 1.23.3 and update dependencies**
- **refactor: update devnet and testnet configurations**
- **feat: add IPFS configuration for devnet**
- **I'll help you update the ipfs.config.pkl to include all the peers
from the shell script. Here's the updated configuration:**
- **refactor: move mpc package to crypto directory**
- **feat: add BIP32 support for various cryptocurrencies**
- **feat: enhance ATN.pkl with additional capabilities**
- **refactor: simplify smart account and vault attenuation creation**
- **feat: add new capabilities to the Attenuation type**
- **refactor: Rename MPC files for clarity and consistency**
- **feat: add DIDKey support for cryptographic operations**
- **feat: add devnet and testnet deployment configurations**
- **fix: correct key derivation in bip32 package**
- **refactor: rename crypto/bip32 package to crypto/accaddr**
- **fix: remove duplicate indirect dependency**
- **refactor: move vault package to root directory**
- **refactor: update routes for gateway and vault**
- **refactor: remove obsolete web configuration file**
- **refactor: remove unused TigerBeetle imports and update host
configuration**
- **refactor: adjust styles directory path**
- **feat: add broadcastTx and simulateTx functions to gateway**
- **feat: add PinVault handler**
This commit is contained in:
Prad Nukala
2024-12-02 14:27:18 -05:00
committed by GitHub
parent 2a128af227
commit 31bcc21c35
535 changed files with 9357 additions and 10950 deletions
+36
View File
@@ -0,0 +1,36 @@
package auth
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/crypto/mpc"
)
// UCANConfig defines the configuration for UCAN middleware
type UCANConfig struct {
// Skipper defines a function to skip middleware
Skipper func(c echo.Context) bool
// KeySource provides the source for validating UCANs
KeySource mpc.KeyshareSource
// TokenLookup is a string in the form of "<source>:<name>" that is used
// to extract token from the request.
// Optional. Default value "header:Authorization".
// Possible values:
// - "header:<name>"
// - "query:<name>"
// - "param:<name>"
// - "cookie:<name>"
TokenLookup string
// AuthScheme to be used in the Authorization header.
// Optional. Default value "Bearer".
AuthScheme string
}
// DefaultUCANConfig is the default UCAN middleware config
var DefaultUCANConfig = UCANConfig{
Skipper: nil,
TokenLookup: "header:Authorization",
AuthScheme: "Bearer",
}
+119
View File
@@ -0,0 +1,119 @@
package auth
import (
"fmt"
"strings"
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/crypto/mpc"
)
// UCAN returns middleware to validate UCAN tokens
func UCAN(source mpc.KeyshareSource, opts ...Option) echo.MiddlewareFunc {
c := DefaultUCANConfig
for _, opt := range opts {
opt(&c)
}
c.KeySource = source
return UCANWithConfig(c)
}
// UCANWithConfig returns UCAN middleware with custom config
func UCANWithConfig(config UCANConfig) echo.MiddlewareFunc {
// Defaults
if config.Skipper == nil {
config.Skipper = DefaultUCANConfig.Skipper
}
if config.TokenLookup == "" {
config.TokenLookup = DefaultUCANConfig.TokenLookup
}
if config.AuthScheme == "" {
config.AuthScheme = DefaultUCANConfig.AuthScheme
}
// Initialize
parts := strings.Split(config.TokenLookup, ":")
extractor := tokenFromHeader(parts[1], config.AuthScheme)
switch parts[0] {
case "query":
extractor = tokenFromQuery(parts[1])
case "param":
extractor = tokenFromParam(parts[1])
case "cookie":
extractor = tokenFromCookie(parts[1])
}
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
if config.Skipper != nil && config.Skipper(c) {
return next(c)
}
auth, err := extractor(c)
if err != nil {
return echo.NewHTTPError(401, err.Error())
}
parser := config.KeySource.UCANParser()
token, err := parser.ParseAndVerify(c.Request().Context(), auth)
if err != nil {
return echo.NewHTTPError(401, "invalid UCAN token")
}
// Store token in context
c.Set("ucan", token)
return next(c)
}
}
}
// tokenFromHeader extracts token from header
func tokenFromHeader(header string, authScheme string) func(echo.Context) (string, error) {
return func(c echo.Context) (string, error) {
auth := c.Request().Header.Get(header)
if auth == "" {
return "", fmt.Errorf("missing auth token")
}
if authScheme == "" {
return auth, nil
}
l := len(authScheme)
if len(auth) > l+1 && auth[:l] == authScheme {
return auth[l+1:], nil
}
return "", fmt.Errorf("invalid auth scheme")
}
}
// tokenFromQuery extracts token from query string
func tokenFromQuery(param string) func(echo.Context) (string, error) {
return func(c echo.Context) (string, error) {
token := c.QueryParam(param)
if token == "" {
return "", fmt.Errorf("missing auth token")
}
return token, nil
}
}
// tokenFromParam extracts token from url param
func tokenFromParam(param string) func(echo.Context) (string, error) {
return func(c echo.Context) (string, error) {
token := c.Param(param)
if token == "" {
return "", fmt.Errorf("missing auth token")
}
return token, nil
}
}
// tokenFromCookie extracts token from cookie
func tokenFromCookie(name string) func(echo.Context) (string, error) {
return func(c echo.Context) (string, error) {
cookie, err := c.Cookie(name)
if err != nil {
return "", fmt.Errorf("missing auth token")
}
return cookie.Value, nil
}
}
+26
View File
@@ -0,0 +1,26 @@
package auth
import (
"github.com/labstack/echo/v4"
)
type Option func(c *UCANConfig)
func WithSkipper(skipper func(c echo.Context) bool) Option {
return func(c *UCANConfig) {
c.Skipper = skipper
}
}
func WithAuthScheme(scheme string) Option {
return func(c *UCANConfig) {
c.AuthScheme = scheme
}
}
// WithTokenLookup sets the token lookup strategy
func WithTokenLookup(lookup string) Option {
return func(c *UCANConfig) {
c.TokenLookup = lookup
}
}
@@ -16,9 +16,6 @@ const (
// SonrAddress is the key for the Sonr address cookie.
SonrAddress Key = "sonr.address"
// SonrKeyshare is the key for the Sonr address cookie.
SonrKeyshare Key = "sonr.keyshare"
// SonrDID is the key for the Sonr DID cookie.
SonrDID Key = "sonr.did"
@@ -16,8 +16,6 @@ const (
UserAgent Key = "Sec-CH-UA"
// Sonr Injected
ChainID Key = "X-Chain-ID"
IPFSHost Key = "X-Host-IPFS"
SonrAPIURL Key = "X-Sonr-API"
SonrgRPCURL Key = "X-Sonr-GRPC"
SonrRPCURL Key = "X-Sonr-RPC"
-49
View File
@@ -1,49 +0,0 @@
package httputil
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
// FetchAndDecode makes a GET request to the specified URL and decodes the JSON response into the provided type T
func FetchAndDecode[T any](url string) (*T, error) {
// Create HTTP client
client := &http.Client{}
// Create request
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
// Set headers
req.Header.Set("Content-Type", "application/json")
// Make the request
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()
// Check status code
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
// Read body
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
// Decode JSON into generic type
var result T
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("error decoding JSON: %w", err)
}
return &result, nil
}
-1
View File
@@ -1 +0,0 @@
package ipfs
-1
View File
@@ -1 +0,0 @@
package ipfsapi
-1
View File
@@ -1 +0,0 @@
package ipfsget
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package models
type Account struct {
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package models
type Asset struct {
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package models
type Chain struct {
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package models
type Credential struct {
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package models
import (
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package models
type Grant struct {
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package models
type JWK struct {
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package models
type Keyshare struct {
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package models
import (
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package models
type Profile struct {
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package assettype
import (
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package didmethod
import (
+11 -11
View File
@@ -1,17 +1,17 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package models
import "github.com/apple/pkl-go/pkl"
func init() {
pkl.RegisterMapping("common.types.ORM", ORM{})
pkl.RegisterMapping("common.types.ORM#Account", Account{})
pkl.RegisterMapping("common.types.ORM#Asset", Asset{})
pkl.RegisterMapping("common.types.ORM#Chain", Chain{})
pkl.RegisterMapping("common.types.ORM#Credential", Credential{})
pkl.RegisterMapping("common.types.ORM#DID", DID{})
pkl.RegisterMapping("common.types.ORM#JWK", JWK{})
pkl.RegisterMapping("common.types.ORM#Grant", Grant{})
pkl.RegisterMapping("common.types.ORM#Keyshare", Keyshare{})
pkl.RegisterMapping("common.types.ORM#Profile", Profile{})
pkl.RegisterMapping("sonr.motr.ORM", ORM{})
pkl.RegisterMapping("sonr.motr.ORM#Account", Account{})
pkl.RegisterMapping("sonr.motr.ORM#Asset", Asset{})
pkl.RegisterMapping("sonr.motr.ORM#Chain", Chain{})
pkl.RegisterMapping("sonr.motr.ORM#Credential", Credential{})
pkl.RegisterMapping("sonr.motr.ORM#DID", DID{})
pkl.RegisterMapping("sonr.motr.ORM#JWK", JWK{})
pkl.RegisterMapping("sonr.motr.ORM#Grant", Grant{})
pkl.RegisterMapping("sonr.motr.ORM#Keyshare", Keyshare{})
pkl.RegisterMapping("sonr.motr.ORM#Profile", Profile{})
}
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package keyalgorithm
import (
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package keycurve
import (
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package keyencoding
import (
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package keyrole
import (
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package keysharerole
import (
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package keytype
import (
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package permissiongrant
import (
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.ORM`. DO NOT EDIT.
// Code generated from Pkl module `sonr.motr.ORM`. DO NOT EDIT.
package permissionscope
import (
+19
View File
@@ -0,0 +1,19 @@
package response
import (
"net/http"
"github.com/labstack/echo/v4"
)
func RedirectLanding(c echo.Context) error {
return c.Redirect(http.StatusFound, "http://localhost:3000")
}
func RedirectVaultCID(c echo.Context, cid string) error {
return c.Redirect(http.StatusFound, cid)
}
func RedirectVaultIPNS(c echo.Context, ipns string) error {
return c.Redirect(http.StatusFound, ipns)
}
-39
View File
@@ -1,39 +0,0 @@
package common
import (
"reflect"
"strings"
)
const SchemaVersion = 1
func toCamelCase(s string) string {
if s == "" {
return s
}
if len(s) == 1 {
return strings.ToLower(s)
}
return strings.ToLower(s[:1]) + s[1:]
}
func GetSchema(structType interface{}) string {
t := reflect.TypeOf(structType)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return ""
}
var fields []string
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fieldName := toCamelCase(field.Name)
fields = append(fields, fieldName)
}
// Add "++" at the beginning, separated by a comma
return "++, " + strings.Join(fields, ", ")
}
+42
View File
@@ -0,0 +1,42 @@
package session
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/pkg/common/cookie"
"github.com/onsonr/sonr/pkg/common/header"
"github.com/onsonr/sonr/pkg/vault/types"
)
// TODO: Returns fixed chain ID for testing.
func GetChainID(c echo.Context) string {
return "sonr-testnet-1"
}
// GetVaultConfig returns the default vault config
func GetVaultConfig(c echo.Context, addr string, ucanCID string) *types.Config {
return &types.Config{
MotrToken: ucanCID,
MotrAddress: addr,
IpfsGatewayUrl: "http://localhost:80",
SonrApiUrl: "http://localhost:1317",
SonrRpcUrl: "http://localhost:26657",
SonrChainId: GetChainID(c),
VaultSchema: GetVaultSchema(c),
}
}
// GetVaultSchema returns the default vault schema
func GetVaultSchema(c echo.Context) *types.Schema {
return types.DefaultSchema()
}
// SetVaultAddress sets the address of the vault
func SetVaultAddress(c echo.Context, address string) error {
return cookie.Write(c, cookie.SonrAddress, address)
}
// SetVaultAuthorization sets the UCAN CID of the vault
func SetVaultAuthorization(c echo.Context, ucanCID string) error {
header.Write(c, header.Authorization, formatAuth(ucanCID))
return nil
}
@@ -6,9 +6,9 @@ import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/pkg/common"
"github.com/onsonr/sonr/pkg/common/middleware/cookie"
"github.com/onsonr/sonr/pkg/common/middleware/header"
"github.com/onsonr/sonr/pkg/core/dwn"
"github.com/onsonr/sonr/pkg/common/cookie"
"github.com/onsonr/sonr/pkg/common/header"
"github.com/onsonr/sonr/pkg/vault/types"
)
// HwayMiddleware establishes a Session Cookie.
@@ -22,7 +22,7 @@ func HwayMiddleware() echo.MiddlewareFunc {
}
// MotrMiddleware establishes a Session Cookie.
func MotrMiddleware(config *dwn.Config) echo.MiddlewareFunc {
func MotrMiddleware(config *types.Config) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
err := injectConfig(c, config)
@@ -35,16 +35,11 @@ func MotrMiddleware(config *dwn.Config) echo.MiddlewareFunc {
}
}
func injectConfig(c echo.Context, config *dwn.Config) error {
header.Write(c, header.IPFSHost, config.IpfsGatewayUrl)
header.Write(c, header.ChainID, config.SonrChainId)
func injectConfig(c echo.Context, config *types.Config) error {
header.Write(c, header.SonrAPIURL, config.SonrApiUrl)
header.Write(c, header.SonrRPCURL, config.SonrRpcUrl)
cookie.Write(c, cookie.SonrAddress, config.MotrAddress)
cookie.Write(c, cookie.SonrKeyshare, config.MotrKeyshare)
schemaBz, err := json.Marshal(config.VaultSchema)
if err != nil {
return err
@@ -58,16 +53,16 @@ func injectSession(c echo.Context, role common.PeerRole) *HTTPContext {
if c == nil {
return initHTTPContext(nil)
}
cookie.Write(c, cookie.SessionRole, role.String())
// Continue even if there are errors, just ensure we have valid session data
if err := loadOrGenKsuid(c); err != nil {
// Log error but continue
}
if err := loadOrGenChallenge(c); err != nil {
// Log error but continue
// Log error but continue
}
return initHTTPContext(c)
}
@@ -6,7 +6,7 @@ import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/pkg/common"
"github.com/onsonr/sonr/pkg/common/middleware/cookie"
"github.com/onsonr/sonr/pkg/common/cookie"
"github.com/onsonr/sonr/pkg/common/types"
)
@@ -41,18 +41,18 @@ func initHTTPContext(c echo.Context) *HTTPContext {
sessionData: &types.Session{},
}
}
sessionData := injectSessionData(c)
if sessionData == nil {
sessionData = &types.Session{}
}
cc := &HTTPContext{
Context: c,
role: common.PeerRole(cookie.ReadUnsafe(c, cookie.SessionRole)),
sessionData: sessionData,
}
// Set the session data in both contexts
c.SetRequest(c.Request().WithContext(WithData(c.Request().Context(), sessionData)))
return cc
@@ -10,8 +10,8 @@ import (
"github.com/segmentio/ksuid"
"github.com/onsonr/sonr/pkg/common"
"github.com/onsonr/sonr/pkg/common/middleware/cookie"
"github.com/onsonr/sonr/pkg/common/middleware/header"
"github.com/onsonr/sonr/pkg/common/cookie"
"github.com/onsonr/sonr/pkg/common/header"
"github.com/onsonr/sonr/pkg/common/types"
)
@@ -186,3 +186,7 @@ func baseRegisterOptions() *common.RegisterOptions {
},
}
}
func formatAuth(ucanCID string) string {
return "Bearer " + ucanCID
}
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.Ctx`. DO NOT EDIT.
// Code generated from Pkl module `sonr.hway.Ctx`. DO NOT EDIT.
package types
import (
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated from Pkl module `common.types.Ctx`. DO NOT EDIT.
// Code generated from Pkl module `sonr.hway.Ctx`. DO NOT EDIT.
package types
type Session struct {
+3 -3
View File
@@ -1,9 +1,9 @@
// Code generated from Pkl module `common.types.Ctx`. DO NOT EDIT.
// Code generated from Pkl module `sonr.hway.Ctx`. DO NOT EDIT.
package types
import "github.com/apple/pkl-go/pkl"
func init() {
pkl.RegisterMapping("common.types.Ctx", Ctx{})
pkl.RegisterMapping("common.types.Ctx#Session", Session{})
pkl.RegisterMapping("sonr.hway.Ctx", Ctx{})
pkl.RegisterMapping("sonr.hway.Ctx#Session", Session{})
}