mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-04 02:11:40 +00:00
feature/1115 execute ucan token (#1177)
- **deps: remove tigerbeetle-go dependency** - **refactor: remove unused landing page components and models** - **feat: add pin and publish vault handlers** - **refactor: move payment and credential services to webui browser package** - **refactor: remove unused credentials management components** - **feat: add landing page components and middleware for credentials and payments** - **refactor: remove unused imports in vault config** - **refactor: remove unused bank, DID, and DWN gRPC clients** - **refactor: rename client files and improve code structure** - **feat: add session middleware helpers and landing page components** - **feat: add user profile registration flow** - **feat: Implement WebAuthn registration flow** - **feat: add error view for users without WebAuthn devices** - **chore: update htmx to include extensions** - **refactor: rename pin handler to claim handler and update routes** - **chore: update import paths after moving UI components and styles** - **fix: address potential server errors by handling and logging them properly** - **refactor: move vault config to gateway package and update related dependencies** - **style: simplify form styling and remove unnecessary components** - **feat: improve UI design for registration flow** - **feat: implement passkey-based authentication** - **refactor: migrate registration forms to use reusable form components** - **refactor: remove tailwindcss setup and use CDN instead** - **style: update submit button style to use outline variant** - **refactor: refactor server and IPFS client, remove MPC encryption** - **refactor: Abstract keyshare functionality and improve message encoding** - **refactor: improve keyset JSON marshaling and error handling** - **feat: add support for digital signatures using MPC keys** - **fix: Refactor MarshalJSON to use standard json.Marshal for Message serialization** - **fix: Encode messages before storing in keyshare structs** - **style: update form input styles for improved user experience** - **refactor: improve code structure in registration handlers** - **refactor: consolidate signer middleware and IPFS interaction** - **refactor: rename MPC signing and refresh protocol functions** - **refactor: update hway configuration loading mechanism** - **feat: integrate database support for sessions and users** - **refactor: remove devnet infrastructure and simplify build process** - **docs(guides): add Sonr DID module guide** - **feat: integrate progress bar into registration form** - **refactor: migrate WebAuthn dependencies to protocol package** - **feat: enhance user registration with passkey integration and improved form styling** - **refactor: move gateway view handlers to internal pages package** - **refactor: Move address package to MPC module** - **feat: integrate turnstile for registration** - **style: remove unnecessary size attribute from buttons** - **refactor: rename cookie package to session/cookie** - **refactor: remove unnecessary types.Session dependency** - **refactor: rename pkg/core to pkg/chain** - **refactor: simplify deployment process by removing testnet-specific Taskfile and devbox configuration** - **feat: add error redirect functionality and improve routes** - **feat: implement custom error handling for gateway** - **chore: update version number to 0.0.7 in template** - **feat: add IPFS client implementation** - **feat: Implement full IPFS client interface with comprehensive methods** - **refactor: improve IPFS client path handling** - **refactor: Move UCAN middleware to controller package** - **feat: add UCAN middleware to motr** - **refactor: update libp2p dependency** - **docs: add UCAN specification document** - **refactor: move UCAN controller logic to common package** - **refactor: rename exports.go to common.go** - **feat: add UCAN token support** - **refactor: migrate UCAN token parsing to dedicated package** - **refactor: improve CometBFT and app config initialization** - **refactor: improve deployment scripts and documentation** - **feat: integrate IPFS and producer middleware** - **refactor: rename agent directory to aider** - **fix: correct libp2p import path** - **refactor: remove redundant dependency** - **cleanup: remove unnecessary test files** - **refactor: move attention types to crypto/ucan package** - **feat: expand capabilities and resource types for UCANs** - **refactor: rename sonr.go to codec.go and update related imports** - **feat: add IPFS-based token store** - **feat: Implement IPFS-based token store with caching and UCAN integration** - **feat: Add dynamic attenuation constructor for UCAN presets** - **fix: Handle missing or invalid attenuation data with EmptyAttenuation** - **fix: Update UCAN attenuation tests with correct capability types** - **feat: integrate UCAN-based authorization into the producer middleware** - **refactor: remove unused dependency on go-ucan** - **refactor: Move address handling logic to DID module** - **feat: Add support for compressed and uncompressed Secp256k1 public keys in didkey** - **test: Add test for generating DID key from MPC keyshares** - **feat: Add methods for extracting compressed and uncompressed public keys in share types** - **feat: Add BaseKeyshare struct with public key conversion methods** - **refactor: Use compressed and uncompressed public keys in keyshare, fix public key usage in tests and verification** - **feat: add support for key generation policy type** - **fix: correct typo in VaultPermissions constant** - **refactor: move JWT related code to ucan package** - **refactor: move UCAN JWT and source code to spec package**
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
// Code generated from Pkl module `sonr.hway.Env`. DO NOT EDIT.
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/apple/pkl-go/pkl"
|
||||
)
|
||||
|
||||
type Env interface {
|
||||
GetServePort() int
|
||||
|
||||
GetConfigDir() string
|
||||
|
||||
GetSqliteFile() string
|
||||
|
||||
GetChainId() string
|
||||
|
||||
GetIpfsGatewayUrl() string
|
||||
|
||||
GetSonrApiUrl() string
|
||||
|
||||
GetSonrGrpcUrl() string
|
||||
|
||||
GetSonrRpcUrl() string
|
||||
|
||||
GetTurnstileSiteKey() string
|
||||
}
|
||||
|
||||
var _ Env = (*EnvImpl)(nil)
|
||||
|
||||
type EnvImpl struct {
|
||||
ServePort int `pkl:"servePort"`
|
||||
|
||||
ConfigDir string `pkl:"configDir"`
|
||||
|
||||
SqliteFile string `pkl:"sqliteFile"`
|
||||
|
||||
ChainId string `pkl:"chainId"`
|
||||
|
||||
IpfsGatewayUrl string `pkl:"ipfsGatewayUrl"`
|
||||
|
||||
SonrApiUrl string `pkl:"sonrApiUrl"`
|
||||
|
||||
SonrGrpcUrl string `pkl:"sonrGrpcUrl"`
|
||||
|
||||
SonrRpcUrl string `pkl:"sonrRpcUrl"`
|
||||
|
||||
TurnstileSiteKey string `pkl:"turnstileSiteKey"`
|
||||
}
|
||||
|
||||
func (rcv *EnvImpl) GetServePort() int {
|
||||
return rcv.ServePort
|
||||
}
|
||||
|
||||
func (rcv *EnvImpl) GetConfigDir() string {
|
||||
return rcv.ConfigDir
|
||||
}
|
||||
|
||||
func (rcv *EnvImpl) GetSqliteFile() string {
|
||||
return rcv.SqliteFile
|
||||
}
|
||||
|
||||
func (rcv *EnvImpl) GetChainId() string {
|
||||
return rcv.ChainId
|
||||
}
|
||||
|
||||
func (rcv *EnvImpl) GetIpfsGatewayUrl() string {
|
||||
return rcv.IpfsGatewayUrl
|
||||
}
|
||||
|
||||
func (rcv *EnvImpl) GetSonrApiUrl() string {
|
||||
return rcv.SonrApiUrl
|
||||
}
|
||||
|
||||
func (rcv *EnvImpl) GetSonrGrpcUrl() string {
|
||||
return rcv.SonrGrpcUrl
|
||||
}
|
||||
|
||||
func (rcv *EnvImpl) GetSonrRpcUrl() string {
|
||||
return rcv.SonrRpcUrl
|
||||
}
|
||||
|
||||
func (rcv *EnvImpl) GetTurnstileSiteKey() string {
|
||||
return rcv.TurnstileSiteKey
|
||||
}
|
||||
|
||||
// LoadFromPath loads the pkl module at the given path and evaluates it into a Env
|
||||
func LoadFromPath(ctx context.Context, path string) (ret Env, err error) {
|
||||
evaluator, err := pkl.NewEvaluator(ctx, pkl.PreconfiguredOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
cerr := evaluator.Close()
|
||||
if err == nil {
|
||||
err = cerr
|
||||
}
|
||||
}()
|
||||
ret, err = Load(ctx, evaluator, pkl.FileSource(path))
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Load loads the pkl module at the given source and evaluates it with the given evaluator into a Env
|
||||
func Load(ctx context.Context, evaluator pkl.Evaluator, source *pkl.ModuleSource) (Env, error) {
|
||||
var ret EnvImpl
|
||||
if err := evaluator.EvaluateModule(ctx, source, &ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ret, nil
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/apple/pkl-go/pkl"
|
||||
)
|
||||
|
||||
// LoadFromBytes loads the environment from the given bytes
|
||||
func LoadFromBytes(data []byte) (Env, error) {
|
||||
text := string(data)
|
||||
return LoadFromString(text)
|
||||
}
|
||||
|
||||
// LoadFromString loads the environment from the given string
|
||||
func LoadFromString(text string) (Env, error) {
|
||||
evaluator, err := pkl.NewEvaluator(context.Background(), pkl.PreconfiguredOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
cerr := evaluator.Close()
|
||||
if err == nil {
|
||||
err = cerr
|
||||
}
|
||||
}()
|
||||
ret, err := Load(context.Background(), evaluator, pkl.TextSource(text))
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// LoadFromURL loads the environment from the given URL
|
||||
func LoadFromURL(url string) (Env, error) {
|
||||
evaluator, err := pkl.NewEvaluator(context.Background(), pkl.PreconfiguredOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
cerr := evaluator.Close()
|
||||
if err == nil {
|
||||
err = cerr
|
||||
}
|
||||
}()
|
||||
ret, err := Load(context.Background(), evaluator, pkl.UriSource(url))
|
||||
return ret, err
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Code generated from Pkl module `sonr.hway.Env`. DO NOT EDIT.
|
||||
package config
|
||||
|
||||
import "github.com/apple/pkl-go/pkl"
|
||||
|
||||
func init() {
|
||||
pkl.RegisterMapping("sonr.hway.Env", EnvImpl{})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package embed
|
||||
package internal
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
@@ -0,0 +1,124 @@
|
||||
package config
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
func newWebManifestBytes() ([]byte, error) {
|
||||
return json.Marshal(baseWebManifest)
|
||||
}
|
||||
|
||||
var baseWebManifest = WebManifest{
|
||||
Name: "Sonr Vault",
|
||||
ShortName: "Sonr.ID",
|
||||
StartURL: "/index.html",
|
||||
Display: "standalone",
|
||||
DisplayOverride: []string{
|
||||
"fullscreen",
|
||||
"minimal-ui",
|
||||
},
|
||||
Icons: []IconDefinition{
|
||||
{
|
||||
Src: "/icons/icon-192x192.png",
|
||||
Sizes: "192x192",
|
||||
Type: "image/png",
|
||||
},
|
||||
},
|
||||
ServiceWorker: ServiceWorker{
|
||||
Scope: "/",
|
||||
Src: "/sw.js",
|
||||
UseCache: true,
|
||||
},
|
||||
ProtocolHandlers: []ProtocolHandler{
|
||||
{
|
||||
Scheme: "did.sonr",
|
||||
URL: "/resolve/sonr/%s",
|
||||
},
|
||||
{
|
||||
Scheme: "did.eth",
|
||||
URL: "/resolve/eth/%s",
|
||||
},
|
||||
{
|
||||
Scheme: "did.btc",
|
||||
URL: "/resolve/btc/%s",
|
||||
},
|
||||
{
|
||||
Scheme: "did.usdc",
|
||||
URL: "/resolve/usdc/%s",
|
||||
},
|
||||
{
|
||||
Scheme: "did.ipfs",
|
||||
URL: "/resolve/ipfs/%s",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type WebManifest struct {
|
||||
// Required fields
|
||||
Name string `json:"name"` // Full name of the application
|
||||
ShortName string `json:"short_name"` // Short version of the name
|
||||
|
||||
// Display and appearance
|
||||
Description string `json:"description,omitempty"` // Purpose and features of the application
|
||||
Display string `json:"display,omitempty"` // Preferred display mode: fullscreen, standalone, minimal-ui, browser
|
||||
DisplayOverride []string `json:"display_override,omitempty"`
|
||||
ThemeColor string `json:"theme_color,omitempty"` // Default theme color for the application
|
||||
BackgroundColor string `json:"background_color,omitempty"` // Background color during launch
|
||||
Orientation string `json:"orientation,omitempty"` // Default orientation: any, natural, landscape, portrait
|
||||
|
||||
// URLs and scope
|
||||
StartURL string `json:"start_url"` // Starting URL when launching
|
||||
Scope string `json:"scope,omitempty"` // Navigation scope of the web application
|
||||
ServiceWorker ServiceWorker `json:"service_worker,omitempty"`
|
||||
|
||||
// Icons
|
||||
Icons []IconDefinition `json:"icons,omitempty"`
|
||||
|
||||
// Optional features
|
||||
RelatedApplications []RelatedApplication `json:"related_applications,omitempty"`
|
||||
PreferRelatedApplications bool `json:"prefer_related_applications,omitempty"`
|
||||
Shortcuts []Shortcut `json:"shortcuts,omitempty"`
|
||||
|
||||
// Experimental features (uncomment if needed)
|
||||
FileHandlers []FileHandler `json:"file_handlers,omitempty"`
|
||||
ProtocolHandlers []ProtocolHandler `json:"protocol_handlers,omitempty"`
|
||||
}
|
||||
|
||||
type FileHandler struct {
|
||||
Action string `json:"action"`
|
||||
Accept map[string][]string `json:"accept"`
|
||||
}
|
||||
|
||||
type LaunchHandler struct {
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
type IconDefinition struct {
|
||||
Src string `json:"src"`
|
||||
Sizes string `json:"sizes"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Purpose string `json:"purpose,omitempty"`
|
||||
}
|
||||
|
||||
type ProtocolHandler struct {
|
||||
Scheme string `json:"scheme"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
type RelatedApplication struct {
|
||||
Platform string `json:"platform"`
|
||||
URL string `json:"url,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
type Shortcut struct {
|
||||
Name string `json:"name"`
|
||||
ShortName string `json:"short_name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
URL string `json:"url"`
|
||||
Icons []IconDefinition `json:"icons,omitempty"`
|
||||
}
|
||||
|
||||
type ServiceWorker struct {
|
||||
Scope string `json:"scope"`
|
||||
Src string `json:"src"`
|
||||
UseCache bool `json:"use_cache"`
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/onsonr/sonr/pkg/common/models"
|
||||
"github.com/onsonr/sonr/pkg/vault/types"
|
||||
)
|
||||
|
||||
// DefaultSchema returns the default schema
|
||||
func DefaultSchema() *types.Schema {
|
||||
return &types.Schema{
|
||||
Version: SchemaVersion,
|
||||
Account: getSchema(&models.Account{}),
|
||||
Asset: getSchema(&models.Asset{}),
|
||||
Chain: getSchema(&models.Chain{}),
|
||||
Credential: getSchema(&models.Credential{}),
|
||||
Grant: getSchema(&models.Grant{}),
|
||||
Keyshare: getSchema(&models.Keyshare{}),
|
||||
Profile: getSchema(&models.Profile{}),
|
||||
}
|
||||
}
|
||||
|
||||
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, ", ")
|
||||
}
|
||||
|
||||
func toCamelCase(s string) string {
|
||||
if s == "" {
|
||||
return s
|
||||
}
|
||||
if len(s) == 1 {
|
||||
return strings.ToLower(s)
|
||||
}
|
||||
return strings.ToLower(s[:1]) + s[1:]
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ipfs/boxo/files"
|
||||
"github.com/onsonr/sonr/pkg/gateway/config/internal"
|
||||
"github.com/onsonr/sonr/pkg/vault/types"
|
||||
)
|
||||
|
||||
const SchemaVersion = 1
|
||||
const (
|
||||
AppManifestFileName = "app.webmanifest"
|
||||
DWNConfigFileName = "dwn.json"
|
||||
IndexHTMLFileName = "index.html"
|
||||
MainJSFileName = "main.js"
|
||||
ServiceWorkerFileName = "sw.js"
|
||||
)
|
||||
|
||||
// spawnVaultDirectory creates a new directory with the default files
|
||||
func NewFS(cfg *types.Config) (files.Directory, error) {
|
||||
manifestBz, err := newWebManifestBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cnfBz, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return files.NewMapDirectory(map[string]files.Node{
|
||||
AppManifestFileName: files.NewBytesFile(manifestBz),
|
||||
DWNConfigFileName: files.NewBytesFile(cnfBz),
|
||||
IndexHTMLFileName: files.NewBytesFile(internal.IndexHTML),
|
||||
MainJSFileName: files.NewBytesFile(internal.MainJS),
|
||||
ServiceWorkerFileName: files.NewBytesFile(internal.WorkerJS),
|
||||
}), nil
|
||||
}
|
||||
|
||||
// GetVaultConfig returns the default vault config
|
||||
func GetVaultConfig(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: "sonr-testnet-1",
|
||||
VaultSchema: DefaultSchema(),
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package embed
|
||||
|
||||
import (
|
||||
"github.com/ipfs/boxo/files"
|
||||
)
|
||||
|
||||
const (
|
||||
AppManifestFileName = "app.webmanifest"
|
||||
DWNConfigFileName = "dwn.json"
|
||||
IndexHTMLFileName = "index.html"
|
||||
MainJSFileName = "main.js"
|
||||
ServiceWorkerFileName = "sw.js"
|
||||
)
|
||||
|
||||
// spawnVaultDirectory creates a new directory with the default files
|
||||
func NewFS(cfgBz []byte, manifestBz []byte) files.Directory {
|
||||
return files.NewMapDirectory(map[string]files.Node{
|
||||
AppManifestFileName: files.NewBytesFile(manifestBz),
|
||||
DWNConfigFileName: files.NewBytesFile(cfgBz),
|
||||
IndexHTMLFileName: files.NewBytesFile(IndexHTML),
|
||||
MainJSFileName: files.NewBytesFile(MainJS),
|
||||
ServiceWorkerFileName: files.NewBytesFile(WorkerJS),
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/onsonr/sonr/pkg/common/response"
|
||||
"github.com/onsonr/sonr/pkg/gateway/internal/pages/index"
|
||||
"github.com/onsonr/sonr/pkg/gateway/internal/session"
|
||||
)
|
||||
|
||||
func HandleIndex(c echo.Context) error {
|
||||
if isInitial(c) {
|
||||
return response.TemplEcho(c, index.InitialView())
|
||||
}
|
||||
if isExpired(c) {
|
||||
return response.TemplEcho(c, index.ReturningView())
|
||||
}
|
||||
return c.Render(http.StatusOK, "index.templ", nil)
|
||||
}
|
||||
|
||||
// ╭─────────────────────────────────────────────────────────╮
|
||||
// │ Utility Functions │
|
||||
// ╰─────────────────────────────────────────────────────────╯
|
||||
|
||||
// Initial users have no authorization, user handle, or vault address
|
||||
func isInitial(c echo.Context) bool {
|
||||
noAuth := !session.HasAuthorization(c)
|
||||
noUserHandle := !session.HasUserHandle(c)
|
||||
noVaultAddress := !session.HasVaultAddress(c)
|
||||
return noUserHandle && noVaultAddress && noAuth
|
||||
}
|
||||
|
||||
// Expired users have either a user handle or vault address
|
||||
func isExpired(c echo.Context) bool {
|
||||
noAuth := !session.HasAuthorization(c)
|
||||
hasUserHandle := session.HasUserHandle(c)
|
||||
hasVaultAddress := session.HasVaultAddress(c)
|
||||
return noAuth && hasUserHandle || noAuth && hasVaultAddress
|
||||
}
|
||||
|
||||
// Returning users have a valid authorization, and either a user handle or vault address
|
||||
func isReturning(c echo.Context) bool {
|
||||
hasAuth := session.HasAuthorization(c)
|
||||
hasUserHandle := session.HasUserHandle(c)
|
||||
hasVaultAddress := session.HasVaultAddress(c)
|
||||
return hasAuth && (hasUserHandle || hasVaultAddress)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package handlers
|
||||
|
||||
import "github.com/labstack/echo/v4"
|
||||
|
||||
func HandleLogin(c echo.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
// func LoginHandler(c echo.Context) error {
|
||||
// options := PublicKeyCredentialRequestOptions{
|
||||
// Challenge: "your-challenge-base64url",
|
||||
// RpID: "yourdomain.com",
|
||||
// Timeout: 60000,
|
||||
// AllowCredentials: []CredentialDescriptor{
|
||||
// {
|
||||
// Type: "public-key",
|
||||
// ID: "credential-id-base64url",
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// return GetCredentials(c, options)
|
||||
// }
|
||||
@@ -1,11 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import "github.com/labstack/echo/v4"
|
||||
|
||||
func PinVault(c echo.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func PublishVault(c echo.Context) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/cosmos/btcutil/bech32"
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
"github.com/go-webauthn/webauthn/protocol/webauthncose"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/onsonr/sonr/crypto/mpc"
|
||||
"github.com/onsonr/sonr/pkg/common"
|
||||
"github.com/onsonr/sonr/pkg/common/response"
|
||||
"github.com/onsonr/sonr/pkg/gateway/config"
|
||||
"github.com/onsonr/sonr/pkg/gateway/internal/pages/register"
|
||||
"github.com/onsonr/sonr/pkg/gateway/internal/session"
|
||||
)
|
||||
|
||||
func HandleRegisterView(env config.Env) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
return response.TemplEcho(c, register.ProfileFormView(env.GetTurnstileSiteKey()))
|
||||
}
|
||||
}
|
||||
|
||||
func HandleRegisterStart(c echo.Context) error {
|
||||
firstName := c.FormValue("first_name")
|
||||
lastName := c.FormValue("last_name")
|
||||
handle := c.FormValue("handle")
|
||||
|
||||
if firstName == "" || lastName == "" || handle == "" {
|
||||
return response.RedirectLanding(c)
|
||||
}
|
||||
|
||||
ks, err := mpc.NewKeyset()
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
adr, err := bech32.Encode("idx", ks.Val().GetPublicKey())
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
req := getLinkCredentialRequest(c, adr, handle, ks.UserJSON())
|
||||
return response.TemplEcho(c, register.LinkCredentialView(req))
|
||||
}
|
||||
|
||||
func HandleRegisterFinish(c echo.Context) error {
|
||||
// cred := c.FormValue("credential")
|
||||
return response.TemplEcho(c, register.LoadingVaultView())
|
||||
}
|
||||
|
||||
// ╭───────────────────────────────────────────────────────────╮
|
||||
// │ Registration Components │
|
||||
// ╰───────────────────────────────────────────────────────────╯
|
||||
|
||||
func getLinkCredentialRequest(c echo.Context, addr string, handle string, userKSJSON string) register.LinkCredentialRequest {
|
||||
cc, err := session.Get(c)
|
||||
if err != nil {
|
||||
return register.LinkCredentialRequest{
|
||||
Handle: handle,
|
||||
Address: addr,
|
||||
RegisterOptions: buildRegisterOptions(buildUserEntity(addr, handle), buildLargeBlob(userKSJSON), buildServiceEntity(c)),
|
||||
}
|
||||
}
|
||||
usr := buildUserEntity(addr, handle)
|
||||
blob := buildLargeBlob(userKSJSON)
|
||||
service := buildServiceEntity(c)
|
||||
|
||||
return register.LinkCredentialRequest{
|
||||
Platform: cc.BrowserName(),
|
||||
Handle: handle,
|
||||
DeviceModel: cc.BrowserVersion(),
|
||||
Address: addr,
|
||||
RegisterOptions: buildRegisterOptions(usr, blob, service),
|
||||
}
|
||||
}
|
||||
|
||||
func buildRegisterOptions(user protocol.UserEntity, blob common.LargeBlob, service protocol.RelyingPartyEntity) protocol.PublicKeyCredentialCreationOptions {
|
||||
return protocol.PublicKeyCredentialCreationOptions{
|
||||
Timeout: 10000,
|
||||
Attestation: protocol.PreferDirectAttestation,
|
||||
AuthenticatorSelection: protocol.AuthenticatorSelection{
|
||||
AuthenticatorAttachment: "platform",
|
||||
ResidentKey: protocol.ResidentKeyRequirementPreferred,
|
||||
UserVerification: "preferred",
|
||||
},
|
||||
RelyingParty: service,
|
||||
User: user,
|
||||
Extensions: protocol.AuthenticationExtensions{
|
||||
"largeBlob": blob,
|
||||
},
|
||||
Parameters: []protocol.CredentialParameter{
|
||||
{
|
||||
Type: "public-key",
|
||||
Algorithm: webauthncose.AlgES256,
|
||||
},
|
||||
{
|
||||
Type: "public-key",
|
||||
Algorithm: webauthncose.AlgES256K,
|
||||
},
|
||||
{
|
||||
Type: "public-key",
|
||||
Algorithm: webauthncose.AlgEdDSA,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func buildLargeBlob(userKeyshareJSON string) common.LargeBlob {
|
||||
return common.LargeBlob{
|
||||
Support: "required",
|
||||
Write: userKeyshareJSON,
|
||||
}
|
||||
}
|
||||
|
||||
func buildUserEntity(userAddress string, userHandle string) protocol.UserEntity {
|
||||
return protocol.UserEntity{
|
||||
ID: userAddress,
|
||||
DisplayName: userHandle,
|
||||
CredentialEntity: protocol.CredentialEntity{
|
||||
Name: userAddress,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func buildServiceEntity(c echo.Context) protocol.RelyingPartyEntity {
|
||||
return protocol.RelyingPartyEntity{
|
||||
CredentialEntity: protocol.CredentialEntity{
|
||||
Name: "Sonr.ID",
|
||||
},
|
||||
ID: c.Request().Host,
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/onsonr/sonr/crypto/mpc"
|
||||
"github.com/onsonr/sonr/pkg/common/session"
|
||||
"github.com/onsonr/sonr/pkg/gateway/embed"
|
||||
"github.com/onsonr/sonr/pkg/gateway/middleware"
|
||||
"github.com/onsonr/sonr/pkg/vault/types"
|
||||
)
|
||||
|
||||
func SpawnVault(c echo.Context) error {
|
||||
ipfs, err := middleware.GetIPFSClient(c)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
ks, err := mpc.NewKeyset()
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
src, err := mpc.NewSource(ks)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
tk, err := src.OriginToken()
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
// Create the vault keyshare auth token
|
||||
kscid, err := tk.CID()
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
// Create the vault config
|
||||
cfg := session.GetVaultConfig(c, src.Address(), kscid.String())
|
||||
cnf, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
// Create the vault app manifest
|
||||
manifest := types.NewWebManifest()
|
||||
manifestBz, err := json.Marshal(manifest)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
dir := embed.NewFS(cnf, manifestBz)
|
||||
path, err := ipfs.Unixfs().Add(c.Request().Context(), dir)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
return c.Redirect(http.StatusFound, path.String())
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package handlers
|
||||
|
||||
//
|
||||
// type SpawnVaultRequest struct {
|
||||
// Name string `json:"name"`
|
||||
// }
|
||||
//
|
||||
// func SpawnVault(c echo.Context) error {
|
||||
// ks, err := mpc.NewKeyset()
|
||||
// if err != nil {
|
||||
// return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
// }
|
||||
// src, err := mpc.NewSource(ks)
|
||||
// if err != nil {
|
||||
// return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
// }
|
||||
// tk, err := src.OriginToken()
|
||||
// if err != nil {
|
||||
// return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
// }
|
||||
// // Create the vault keyshare auth token
|
||||
// kscid, err := tk.CID()
|
||||
// if err != nil {
|
||||
// return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
// }
|
||||
// // Create the vault config
|
||||
// dir, err := config.NewFS(config.GetVaultConfig(src.Address(), kscid.String()))
|
||||
// path, err := clients.IPFSAdd(c, dir)
|
||||
// if err != nil {
|
||||
// return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
||||
// }
|
||||
// return c.Redirect(http.StatusFound, path)
|
||||
// }
|
||||
@@ -0,0 +1,16 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidCredentials = echo.NewHTTPError(http.StatusUnauthorized, "Invalid credentials")
|
||||
ErrInvalidSubject = echo.NewHTTPError(http.StatusBadRequest, "Invalid subject")
|
||||
ErrInvalidUser = echo.NewHTTPError(http.StatusBadRequest, "Invalid user")
|
||||
|
||||
ErrUserAlreadyExists = echo.NewHTTPError(http.StatusConflict, "User already exists")
|
||||
ErrUserNotFound = echo.NewHTTPError(http.StatusNotFound, "User not found")
|
||||
)
|
||||
@@ -0,0 +1,57 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/onsonr/sonr/pkg/gateway/config"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DatabaseContext struct {
|
||||
echo.Context
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func Middleware(env config.Env) echo.MiddlewareFunc {
|
||||
cc := initDB(env.GetSqliteFile())
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
cc.Context = c
|
||||
return next(cc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DatabaseContext) HasDB() bool {
|
||||
return c.db != nil
|
||||
}
|
||||
|
||||
func initDB(path string) *DatabaseContext {
|
||||
cc := new(DatabaseContext)
|
||||
db, err := gorm.Open(sqlite.Open(path), &gorm.Config{})
|
||||
if err != nil {
|
||||
cc.db = nil
|
||||
return cc
|
||||
}
|
||||
// Migrate the schema
|
||||
db.AutoMigrate(&Session{})
|
||||
db.AutoMigrate(&User{})
|
||||
|
||||
return &DatabaseContext{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func formatDBPath(path string) string {
|
||||
home := os.Getenv("HOME")
|
||||
if home == "" {
|
||||
home = os.Getenv("USERPROFILE")
|
||||
}
|
||||
if home == "" {
|
||||
home = "."
|
||||
}
|
||||
return filepath.Join(home, ".config", "hway", path)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package database
|
||||
|
||||
type Session struct {
|
||||
ID string `json:"id"`
|
||||
BrowserName string `json:"browserName"`
|
||||
BrowserVersion string `json:"browserVersion"`
|
||||
UserArchitecture string `json:"userArchitecture"`
|
||||
Platform string `json:"platform"`
|
||||
PlatformVersion string `json:"platformVersion"`
|
||||
DeviceModel string `json:"deviceModel"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Address string `json:"address"`
|
||||
Handle string `json:"handle"`
|
||||
FirstName string `json:"firstName"`
|
||||
LastName string `json:"lastName"`
|
||||
VaultCID string `json:"vaultCID"`
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package index
|
||||
|
||||
import "github.com/onsonr/sonr/pkg/styles/layout"
|
||||
|
||||
templ NoWebauthnErrorView() {
|
||||
@layout.Root("Error | Sonr.ID") {
|
||||
<div class="flex fixed inset-0 z-[99] w-screen h-screen bg-white">
|
||||
<div class="relative flex flex-wrap items-center w-full h-full px-8">
|
||||
<div class="relative w-full max-w-sm mx-auto lg:mb-0">
|
||||
<div class="flex flex-col items-center justify-center h-full">
|
||||
<div class="flex flex-col items-center justify-center h-full">
|
||||
<h1 class="text-3xl font-bold text-zinc-900 mb-4">
|
||||
No WebAuthn Devices
|
||||
</h1>
|
||||
<p class="text-lg text-zinc-500">
|
||||
You don't have any WebAuthn devices connected to your computer.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col items-center justify-center h-full">
|
||||
<button class="btn btn-sm text-zinc-100 bg-zinc-900 hover:bg-zinc-800 w-full shadow">
|
||||
Get Started
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.793
|
||||
package index
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import templruntime "github.com/a-h/templ/runtime"
|
||||
|
||||
import "github.com/onsonr/sonr/pkg/styles/layout"
|
||||
|
||||
func NoWebauthnErrorView() templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex fixed inset-0 z-[99] w-screen h-screen bg-white\"><div class=\"relative flex flex-wrap items-center w-full h-full px-8\"><div class=\"relative w-full max-w-sm mx-auto lg:mb-0\"><div class=\"flex flex-col items-center justify-center h-full\"><div class=\"flex flex-col items-center justify-center h-full\"><h1 class=\"text-3xl font-bold text-zinc-900 mb-4\">No WebAuthn Devices</h1><p class=\"text-lg text-zinc-500\">You don't have any WebAuthn devices connected to your computer.</p></div><div class=\"flex flex-col items-center justify-center h-full\"><button class=\"btn btn-sm text-zinc-100 bg-zinc-900 hover:bg-zinc-800 w-full shadow\">Get Started</button></div></div></div></div></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = layout.Root("Error | Sonr.ID").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
@@ -0,0 +1,36 @@
|
||||
package index
|
||||
|
||||
import (
|
||||
"github.com/onsonr/sonr/pkg/styles/layout"
|
||||
"github.com/onsonr/sonr/pkg/styles/text"
|
||||
)
|
||||
|
||||
templ InitialView() {
|
||||
@layout.Root("Welcome | Sonr.ID") {
|
||||
@layout.Container() {
|
||||
@text.Header("Sonr.ID", "The decentralized identity layer for the web.")
|
||||
<div class="pt-3 flex flex-col items-center justify-center h-full">
|
||||
<sl-button hx-target="#container" hx-get="/register" type="button">
|
||||
<sl-icon slot="prefix" library="sonr" name="sonr"></sl-icon>
|
||||
Get Started
|
||||
<sl-icon slot="suffix" library="sonr" name="arrow-right"></sl-icon>
|
||||
</sl-button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
templ ReturningView() {
|
||||
@layout.Root("Login | Sonr.ID") {
|
||||
@layout.Container() {
|
||||
@text.Header("Welcome Back!", "Continue with your existing Sonr.ID.")
|
||||
<div class="pt-3 flex flex-col items-center justify-center h-full">
|
||||
<sl-button hx-target="#container" hx-get="/register" type="button">
|
||||
<sl-icon slot="prefix" library="sonr" name="sonr"></sl-icon>
|
||||
Log back in
|
||||
<sl-icon slot="suffix" library="sonr" name="arrow-right"></sl-icon>
|
||||
</sl-button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.793
|
||||
package index
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import templruntime "github.com/a-h/templ/runtime"
|
||||
|
||||
import (
|
||||
"github.com/onsonr/sonr/pkg/styles/layout"
|
||||
"github.com/onsonr/sonr/pkg/styles/text"
|
||||
)
|
||||
|
||||
func InitialView() templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var3 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Err = text.Header("Sonr.ID", "The decentralized identity layer for the web.").Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"pt-3 flex flex-col items-center justify-center h-full\"><sl-button hx-target=\"#container\" hx-get=\"/register\" type=\"button\"><sl-icon slot=\"prefix\" library=\"sonr\" name=\"sonr\"></sl-icon> Get Started <sl-icon slot=\"suffix\" library=\"sonr\" name=\"arrow-right\"></sl-icon></sl-button></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = layout.Container().Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = layout.Root("Welcome | Sonr.ID").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
|
||||
func ReturningView() templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var4 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var4 == nil {
|
||||
templ_7745c5c3_Var4 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var5 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var6 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Err = text.Header("Welcome Back!", "Continue with your existing Sonr.ID.").Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"pt-3 flex flex-col items-center justify-center h-full\"><sl-button hx-target=\"#container\" hx-get=\"/register\" type=\"button\"><sl-icon slot=\"prefix\" library=\"sonr\" name=\"sonr\"></sl-icon> Log back in <sl-icon slot=\"suffix\" library=\"sonr\" name=\"arrow-right\"></sl-icon></sl-button></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = layout.Container().Render(templ.WithChildren(ctx, templ_7745c5c3_Var6), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = layout.Root("Login | Sonr.ID").Render(templ.WithChildren(ctx, templ_7745c5c3_Var5), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
@@ -0,0 +1,24 @@
|
||||
package login
|
||||
|
||||
type LoginRequest struct {
|
||||
Subject string
|
||||
Action string
|
||||
Origin string
|
||||
Status string
|
||||
Ping string
|
||||
BlockSpeed string
|
||||
BlockHeight string
|
||||
}
|
||||
|
||||
type PublicKeyCredentialRequestOptions struct {
|
||||
Challenge string `json:"challenge"`
|
||||
RpID string `json:"rpId"`
|
||||
Timeout int `json:"timeout,omitempty"`
|
||||
UserVerification string `json:"userVerification,omitempty"`
|
||||
AllowCredentials []CredentialDescriptor `json:"allowCredentials,omitempty"`
|
||||
}
|
||||
|
||||
type CredentialDescriptor struct {
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id"`
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package register
|
||||
|
||||
import (
|
||||
"github.com/a-h/templ"
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
)
|
||||
|
||||
type LinkCredentialRequest struct {
|
||||
Platform string `json:"platform"`
|
||||
Handle string `json:"handle"`
|
||||
DeviceModel string `json:"deviceModel"`
|
||||
Architecture string `json:"architecture"`
|
||||
Address string `json:"address"`
|
||||
RegisterOptions protocol.PublicKeyCredentialCreationOptions `json:"registerOptions"`
|
||||
}
|
||||
|
||||
func (r LinkCredentialRequest) GetCredentialOptions() string {
|
||||
opts, _ := templ.JSONString(r.RegisterOptions)
|
||||
return opts
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package register
|
||||
|
||||
import (
|
||||
"github.com/onsonr/sonr/pkg/styles/details"
|
||||
"github.com/onsonr/sonr/pkg/styles/form"
|
||||
"github.com/onsonr/sonr/pkg/styles/layout"
|
||||
"github.com/onsonr/sonr/pkg/styles/text"
|
||||
)
|
||||
|
||||
templ ProfileFormView(turnstileSiteKey string) {
|
||||
@layout.Root("Sonr.ID") {
|
||||
@layout.Container() {
|
||||
@text.Header("Create a Profile", "Enter some basic information about yourself.")
|
||||
<br/>
|
||||
@form.Form("/register/start", "POST", form.Submit("Continue"), "25", true) {
|
||||
@form.NameInput()
|
||||
<br/>
|
||||
@form.HandleInput()
|
||||
@form.TurnstileWidget(turnstileSiteKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
templ LinkCredentialView(req LinkCredentialRequest) {
|
||||
@layout.Root("Sonr.ID") {
|
||||
@layout.Container() {
|
||||
@text.Header("Link a PassKey", "This will be used to login to your vault.")
|
||||
<br/>
|
||||
@form.Form("/register/finish", "POST", form.PasskeyInput("passkey"), "65", false) {
|
||||
@details.PropertyList() {
|
||||
@details.Property("Address", req.Address, "wallet")
|
||||
@details.Property("Handle", req.Handle, "at-sign")
|
||||
@details.Property("Platform", req.Platform, "device-iphone")
|
||||
@details.Property("Model", req.DeviceModel, "laptop")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
templ LoadingVaultView() {
|
||||
@layout.Root("Sonr.ID") {
|
||||
@layout.Container() {
|
||||
@text.Header("Loading Vault", "This will be used to login to your vault.")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.793
|
||||
package register
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import templruntime "github.com/a-h/templ/runtime"
|
||||
|
||||
import (
|
||||
"github.com/onsonr/sonr/pkg/styles/details"
|
||||
"github.com/onsonr/sonr/pkg/styles/form"
|
||||
"github.com/onsonr/sonr/pkg/styles/layout"
|
||||
"github.com/onsonr/sonr/pkg/styles/text"
|
||||
)
|
||||
|
||||
func ProfileFormView(turnstileSiteKey string) templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var3 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Err = text.Header("Create a Profile", "Enter some basic information about yourself.").Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <br>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var4 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Err = form.NameInput().Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <br>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = form.HandleInput().Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = form.TurnstileWidget(turnstileSiteKey).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = form.Form("/register/start", "POST", form.Submit("Continue"), "25", true).Render(templ.WithChildren(ctx, templ_7745c5c3_Var4), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = layout.Container().Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = layout.Root("Sonr.ID").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
|
||||
func LinkCredentialView(req LinkCredentialRequest) templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var5 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var5 == nil {
|
||||
templ_7745c5c3_Var5 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var6 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var7 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Err = text.Header("Link a PassKey", "This will be used to login to your vault.").Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <br>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var8 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var9 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Err = details.Property("Address", req.Address, "wallet").Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = details.Property("Handle", req.Handle, "at-sign").Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = details.Property("Platform", req.Platform, "device-iphone").Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = details.Property("Model", req.DeviceModel, "laptop").Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = details.PropertyList().Render(templ.WithChildren(ctx, templ_7745c5c3_Var9), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = form.Form("/register/finish", "POST", form.PasskeyInput("passkey"), "65", false).Render(templ.WithChildren(ctx, templ_7745c5c3_Var8), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = layout.Container().Render(templ.WithChildren(ctx, templ_7745c5c3_Var7), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = layout.Root("Sonr.ID").Render(templ.WithChildren(ctx, templ_7745c5c3_Var6), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
|
||||
func LoadingVaultView() templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var10 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var10 == nil {
|
||||
templ_7745c5c3_Var10 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var11 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var12 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Err = text.Header("Loading Vault", "This will be used to login to your vault.").Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = layout.Container().Render(templ.WithChildren(ctx, templ_7745c5c3_Var12), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = layout.Root("Sonr.ID").Render(templ.WithChildren(ctx, templ_7745c5c3_Var11), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
@@ -0,0 +1,46 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/onsonr/sonr/pkg/common"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
||||
// Context keys
|
||||
const (
|
||||
DataContextKey contextKey = "http_session_data"
|
||||
)
|
||||
|
||||
type SessionCtx interface {
|
||||
ID() string
|
||||
BrowserName() string
|
||||
BrowserVersion() string
|
||||
}
|
||||
|
||||
// Get returns the session.Context from the echo context.
|
||||
func Get(c echo.Context) (SessionCtx, error) {
|
||||
ctx, ok := c.(*HTTPContext)
|
||||
if !ok {
|
||||
return nil, echo.NewHTTPError(http.StatusInternalServerError, "Session Context not found")
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
// TODO: Returns fixed chain ID for testing.
|
||||
func GetChainID(c echo.Context) string {
|
||||
return "sonr-testnet-1"
|
||||
}
|
||||
|
||||
// SetVaultAddress sets the address of the vault
|
||||
func SetVaultAddress(c echo.Context, address string) error {
|
||||
return common.WriteCookie(c, common.SonrAddress, address)
|
||||
}
|
||||
|
||||
// SetVaultAuthorization sets the UCAN CID of the vault
|
||||
func SetVaultAuthorization(c echo.Context, ucanCID string) error {
|
||||
common.HeaderWrite(c, common.Authorization, formatAuth(ucanCID))
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"github.com/onsonr/sonr/pkg/common"
|
||||
"github.com/onsonr/sonr/pkg/gateway/config"
|
||||
)
|
||||
|
||||
// Middleware establishes a Session Cookie.
|
||||
func Middleware(env config.Env) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
cc := injectSession(c, common.RoleHway)
|
||||
return next(cc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// injectSession returns the session injectSession from the cookies.
|
||||
func injectSession(c echo.Context, role common.PeerRole) *HTTPContext {
|
||||
if c == nil {
|
||||
return initHTTPContext(nil)
|
||||
}
|
||||
|
||||
common.WriteCookie(c, common.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
|
||||
}
|
||||
|
||||
return initHTTPContext(c)
|
||||
}
|
||||
|
||||
// HasAuthorization checks if the request has an authorization header
|
||||
func HasAuthorization(c echo.Context) bool {
|
||||
return common.HeaderExists(c, common.Authorization)
|
||||
}
|
||||
|
||||
// HasUserHandle checks if the request has a user handle cookie
|
||||
func HasUserHandle(c echo.Context) bool {
|
||||
return common.CookieExists(c, common.UserHandle)
|
||||
}
|
||||
|
||||
// HasVaultAddress checks if the request has a vault address cookie
|
||||
func HasVaultAddress(c echo.Context) bool {
|
||||
return common.CookieExists(c, common.SonrAddress)
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
"github.com/go-webauthn/webauthn/protocol/webauthncose"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/segmentio/ksuid"
|
||||
|
||||
"github.com/onsonr/sonr/pkg/common"
|
||||
)
|
||||
|
||||
const kWebAuthnTimeout = 6000
|
||||
|
||||
// HTTPContext is the context for HTTP endpoints.
|
||||
type HTTPContext struct {
|
||||
echo.Context
|
||||
role common.PeerRole
|
||||
id string
|
||||
chal string
|
||||
bn string
|
||||
bv string
|
||||
}
|
||||
|
||||
// initHTTPContext loads the headers from the request.
|
||||
func initHTTPContext(c echo.Context) *HTTPContext {
|
||||
if c == nil {
|
||||
return &HTTPContext{}
|
||||
}
|
||||
|
||||
id, chal := extractPeerInfo(c)
|
||||
bn, bv := extractBrowserInfo(c)
|
||||
|
||||
cc := &HTTPContext{
|
||||
Context: c,
|
||||
role: common.PeerRole(common.ReadCookieUnsafe(c, common.SessionRole)),
|
||||
id: id,
|
||||
chal: chal,
|
||||
bn: bn,
|
||||
bv: bv,
|
||||
}
|
||||
|
||||
// Set the session data in both contexts
|
||||
return cc
|
||||
}
|
||||
|
||||
func (s *HTTPContext) ID() string {
|
||||
return s.id
|
||||
}
|
||||
|
||||
func (s *HTTPContext) BrowserName() string {
|
||||
return s.bn
|
||||
}
|
||||
|
||||
func (s *HTTPContext) BrowserVersion() string {
|
||||
return s.bv
|
||||
}
|
||||
|
||||
// ╭───────────────────────────────────────────────────────────╮
|
||||
// │ Initialization │
|
||||
// ╰───────────────────────────────────────────────────────────╯
|
||||
|
||||
func loadOrGenKsuid(c echo.Context) error {
|
||||
var (
|
||||
sessionID string
|
||||
err error
|
||||
)
|
||||
|
||||
// Setup genKsuid function
|
||||
genKsuid := func() string {
|
||||
return ksuid.New().String()
|
||||
}
|
||||
|
||||
// Attempt to read the session ID from the "session" cookie
|
||||
if ok := common.CookieExists(c, common.SessionID); !ok {
|
||||
sessionID = genKsuid()
|
||||
} else {
|
||||
sessionID, err = common.ReadCookie(c, common.SessionID)
|
||||
if err != nil {
|
||||
sessionID = genKsuid()
|
||||
}
|
||||
}
|
||||
common.WriteCookie(c, common.SessionID, sessionID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ╭───────────────────────────────────────────────────────────╮
|
||||
// │ Extraction │
|
||||
// ╰───────────────────────────────────────────────────────────╯
|
||||
|
||||
func extractPeerInfo(c echo.Context) (string, string) {
|
||||
var chal protocol.URLEncodedBase64
|
||||
id, _ := common.ReadCookie(c, common.SessionID)
|
||||
chalRaw, _ := common.ReadCookieBytes(c, common.SessionChallenge)
|
||||
chal.UnmarshalJSON(chalRaw)
|
||||
|
||||
return id, common.Base64Encode(chal)
|
||||
}
|
||||
|
||||
func extractBrowserInfo(c echo.Context) (string, string) {
|
||||
secCHUA := common.HeaderRead(c, common.UserAgent)
|
||||
|
||||
// If common.is empty, return empty BrowserInfo
|
||||
if secCHUA == "" {
|
||||
return "N/A", "-1"
|
||||
}
|
||||
|
||||
// Split the common.into individual browser entries
|
||||
var (
|
||||
name string
|
||||
ver string
|
||||
)
|
||||
entries := strings.Split(strings.TrimSpace(secCHUA), ",")
|
||||
for _, entry := range entries {
|
||||
// Remove leading/trailing spaces and quotes
|
||||
entry = strings.TrimSpace(entry)
|
||||
|
||||
// Use regex to extract the browser name and version
|
||||
re := regexp.MustCompile(`"([^"]+)";v="([^"]+)"`)
|
||||
matches := re.FindStringSubmatch(entry)
|
||||
|
||||
if len(matches) == 3 {
|
||||
browserName := matches[1]
|
||||
version := matches[2]
|
||||
|
||||
// Skip "Not A;Brand"
|
||||
if !validBrowser(browserName) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Store the first valid browser info as fallback
|
||||
name = browserName
|
||||
ver = version
|
||||
}
|
||||
}
|
||||
return name, ver
|
||||
}
|
||||
|
||||
func validBrowser(name string) bool {
|
||||
return name != common.BrowserNameUnknown.String() && name != common.BrowserNameChromium.String()
|
||||
}
|
||||
|
||||
// ╭───────────────────────────────────────────────────────────╮
|
||||
// │ Authentication │
|
||||
// ╰───────────────────────────────────────────────────────────╯
|
||||
|
||||
func buildUserEntity(userID string) protocol.UserEntity {
|
||||
return protocol.UserEntity{
|
||||
ID: userID,
|
||||
}
|
||||
}
|
||||
|
||||
// returns the base options for registering a new user without challenge or user entity.
|
||||
func baseRegisterOptions() *protocol.PublicKeyCredentialCreationOptions {
|
||||
return &protocol.PublicKeyCredentialCreationOptions{
|
||||
Timeout: kWebAuthnTimeout,
|
||||
Attestation: protocol.PreferDirectAttestation,
|
||||
AuthenticatorSelection: protocol.AuthenticatorSelection{
|
||||
AuthenticatorAttachment: "platform",
|
||||
ResidentKey: protocol.ResidentKeyRequirementPreferred,
|
||||
UserVerification: "preferred",
|
||||
},
|
||||
Parameters: []protocol.CredentialParameter{
|
||||
{
|
||||
Type: "public-key",
|
||||
Algorithm: webauthncose.AlgES256,
|
||||
},
|
||||
{
|
||||
Type: "public-key",
|
||||
Algorithm: webauthncose.AlgES256K,
|
||||
},
|
||||
{
|
||||
Type: "public-key",
|
||||
Algorithm: webauthncose.AlgEdDSA,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func formatAuth(ucanCID string) string {
|
||||
return "Bearer " + ucanCID
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ipfs/boxo/files"
|
||||
"github.com/ipfs/kubo/client/rpc"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type IPFSContext struct {
|
||||
echo.Context
|
||||
ipfs *rpc.HttpApi
|
||||
}
|
||||
|
||||
func IPFSMiddleware(client *rpc.HttpApi) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
cc := &IPFSContext{
|
||||
Context: c,
|
||||
ipfs: client,
|
||||
}
|
||||
return next(cc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetIPFSClient(c echo.Context) (*rpc.HttpApi, error) {
|
||||
cc, ok := c.(*IPFSContext)
|
||||
if !ok {
|
||||
return nil, errors.New("not an IPFSContext")
|
||||
}
|
||||
if cc.ipfs == nil {
|
||||
return nil, errors.New("no IPFS client")
|
||||
}
|
||||
return cc.ipfs, nil
|
||||
}
|
||||
|
||||
func getContentType(path string, defaultType string) string {
|
||||
ext := strings.ToLower(filepath.Ext(path))
|
||||
switch ext {
|
||||
case ".html", ".htm":
|
||||
return "text/html"
|
||||
case ".css":
|
||||
return "text/css"
|
||||
case ".js":
|
||||
return "application/javascript"
|
||||
case ".jpg", ".jpeg":
|
||||
return "image/jpeg"
|
||||
case ".png":
|
||||
return "image/png"
|
||||
case ".gif":
|
||||
return "image/gif"
|
||||
case ".svg":
|
||||
return "image/svg+xml"
|
||||
case ".json":
|
||||
return "application/json"
|
||||
case ".xml":
|
||||
return "application/xml"
|
||||
case ".pdf":
|
||||
return "application/pdf"
|
||||
case ".zip":
|
||||
return "application/zip"
|
||||
case ".mp4":
|
||||
return "video/mp4"
|
||||
case ".mp3":
|
||||
return "audio/mpeg"
|
||||
case ".woff":
|
||||
return "font/woff"
|
||||
case ".woff2":
|
||||
return "font/woff2"
|
||||
case ".ttf":
|
||||
return "font/ttf"
|
||||
default:
|
||||
return defaultType
|
||||
}
|
||||
}
|
||||
|
||||
func streamFile(c echo.Context, file files.File, cid string, filePath string) error {
|
||||
// Get file size if possible
|
||||
stat, err := file.Size()
|
||||
if err == nil {
|
||||
c.Response().Header().Set("Content-Length", fmt.Sprintf("%d", stat))
|
||||
}
|
||||
|
||||
// Set content type based on file extension first
|
||||
contentType := getContentType(filePath, "")
|
||||
|
||||
// If no content type found by extension, detect from content
|
||||
if contentType == "" {
|
||||
buffer := make([]byte, 512)
|
||||
_, err = file.Read(buffer)
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
contentType = http.DetectContentType(buffer)
|
||||
|
||||
// Reset file pointer after reading for content type detection
|
||||
if seeker, ok := file.(io.Seeker); ok {
|
||||
_, err = seeker.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set headers
|
||||
c.Response().Header().Set("Content-Type", contentType)
|
||||
c.Response().Header().Set("ETag", fmt.Sprintf(`"%s"`, cid))
|
||||
c.Response().Header().Set("Cache-Control", "public, max-age=29030400, immutable")
|
||||
c.Response().Header().Set("X-Content-Type-Options", "nosniff")
|
||||
c.Response().Header().Set("X-Frame-Options", "DENY")
|
||||
c.Response().Header().Set("X-XSS-Protection", "1; mode=block")
|
||||
|
||||
// Stream the file
|
||||
return c.Stream(http.StatusOK, contentType, file)
|
||||
}
|
||||
|
||||
func redirectOnError(c echo.Context) error {
|
||||
return c.Redirect(http.StatusFound, "http://localhost:3000")
|
||||
}
|
||||
|
||||
func looksLikeCID(s string) bool {
|
||||
return strings.HasPrefix(s, "Qm") || // v0 CID
|
||||
strings.HasPrefix(s, "bafy") || // v1 CID
|
||||
strings.HasPrefix(s, "b") // other base32 v1 CIDs
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package middleware
|
||||
+16
-14
@@ -1,23 +1,25 @@
|
||||
// Package gateway provides the default routes for the Sonr hway.
|
||||
package gateway
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/onsonr/sonr/pkg/common/response"
|
||||
"github.com/onsonr/sonr/pkg/gateway/config"
|
||||
"github.com/onsonr/sonr/pkg/gateway/handlers"
|
||||
"github.com/onsonr/sonr/pkg/gateway/internal/database"
|
||||
"github.com/onsonr/sonr/pkg/gateway/internal/session"
|
||||
)
|
||||
|
||||
func RegisterRoutes(e *echo.Echo) {
|
||||
func RegisterRoutes(e *echo.Echo, env config.Env) {
|
||||
// Custom error handler for gateway
|
||||
e.HTTPErrorHandler = func(err error, c echo.Context) {
|
||||
if he, ok := err.(*echo.HTTPError); ok {
|
||||
// Log the error if needed
|
||||
c.Logger().Errorf("Gateway error: %v", he.Message)
|
||||
}
|
||||
// Redirect to main site
|
||||
c.Redirect(http.StatusFound, "http://localhost:3000")
|
||||
}
|
||||
e.POST("/spawn", handlers.SpawnVault)
|
||||
e.POST("/pin", handlers.PinVault)
|
||||
e.POST("/publish", handlers.PublishVault)
|
||||
e.HTTPErrorHandler = response.RedirectOnError("http://localhost:3000")
|
||||
|
||||
// Inject session middleware
|
||||
e.Use(session.Middleware(env))
|
||||
e.Use(database.Middleware(env))
|
||||
// Register routes
|
||||
e.GET("/", handlers.HandleIndex)
|
||||
e.GET("/register", handlers.HandleRegisterView(env))
|
||||
e.POST("/register/start", handlers.HandleRegisterStart)
|
||||
e.POST("/register/finish", handlers.HandleRegisterFinish)
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
// Code generated from Pkl module `sonr.hway.Gate`. DO NOT EDIT.
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/apple/pkl-go/pkl"
|
||||
)
|
||||
|
||||
type Gate struct {
|
||||
}
|
||||
|
||||
// LoadFromPath loads the pkl module at the given path and evaluates it into a Gate
|
||||
func LoadFromPath(ctx context.Context, path string) (ret *Gate, err error) {
|
||||
evaluator, err := pkl.NewEvaluator(ctx, pkl.PreconfiguredOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
cerr := evaluator.Close()
|
||||
if err == nil {
|
||||
err = cerr
|
||||
}
|
||||
}()
|
||||
ret, err = Load(ctx, evaluator, pkl.FileSource(path))
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Load loads the pkl module at the given source and evaluates it with the given evaluator into a Gate
|
||||
func Load(ctx context.Context, evaluator pkl.Evaluator, source *pkl.ModuleSource) (*Gate, error) {
|
||||
var ret Gate
|
||||
if err := evaluator.EvaluateModule(ctx, source, &ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ret, nil
|
||||
}
|
||||
@@ -4,6 +4,5 @@ package types
|
||||
import "github.com/apple/pkl-go/pkl"
|
||||
|
||||
func init() {
|
||||
pkl.RegisterMapping("sonr.hway.Gate", Gate{})
|
||||
pkl.RegisterMapping("sonr.hway.Gate#Config", Config{})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user