mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
refactor/internal (#1216)
* refactor: update import paths in gateway handlers * refactor: remove obsolete devtools Makefile and README * build: optimize build process for improved efficiency * refactor: remove obsolete pkl files related to Matrix and Sonr network configurations * refactor: move embed code to x/dwn/types
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
|
||||
nodev1beta1 "github.com/cosmos/cosmos-sdk/client/grpc/node"
|
||||
didv1 "github.com/onsonr/sonr/api/did/v1"
|
||||
dwnv1 "github.com/onsonr/sonr/api/dwn/v1"
|
||||
svcv1 "github.com/onsonr/sonr/api/svc/v1"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type (
|
||||
StatusResponse = nodev1beta1.StatusResponse // StatusResponse is the response type for the Service.Status RPC method.
|
||||
StatusRequest = nodev1beta1.StatusRequest // StatusRequest is the request type for the Service.Status RPC method.
|
||||
BalanceRequest = bankv1beta1.QueryBalanceRequest // BalanceRequest is the request type for the Bank.Balance RPC method.
|
||||
BalanceResponse = bankv1beta1.QueryBalanceResponse // BalanceResponse is the response type for the Bank.Balance RPC method.
|
||||
AllBalancesRequest = bankv1beta1.QueryAllBalancesRequest // AllBalancesRequest is the request type for the Bank.AllBalances RPC method.
|
||||
AllBalancesResponse = bankv1beta1.QueryAllBalancesResponse // AllBalancesResponse is the response type for the Bank.AllBalances RPC method.
|
||||
TotalSupplyRequest = bankv1beta1.QueryTotalSupplyRequest // TotalSupplyRequest is the request type for the Bank.TotalSupply RPC method.
|
||||
TotalSupplyResponse = bankv1beta1.QueryTotalSupplyResponse // TotalSupplyResponse is the response type for the Bank.TotalSupply RPC method.
|
||||
DenomMetadataRequest = bankv1beta1.QueryDenomMetadataRequest // DenomMetadataRequest is the request type for the Bank.DenomMetadata RPC method.
|
||||
DenomMetadataResponse = bankv1beta1.QueryDenomMetadataResponse // DenomMetadataResponse is the response type for the Bank.DenomMetadata RPC method.
|
||||
BankParamsRequest = bankv1beta1.QueryParamsRequest // BankParamsRequest is the request type for the Bank.Params RPC method.
|
||||
BankParamsResponse = bankv1beta1.QueryParamsResponse // BankParamsResponse is the response type for the Bank.Params RPC method.
|
||||
DIDParamsRequest = didv1.QueryRequest // DIDParamsRequest is the request type for the DID.Params RPC method.
|
||||
DIDParamsResponse = didv1.QueryParamsResponse // DIDParamsResponse is the response type for the DID.Params RPC method.
|
||||
DIDResolveResponse = didv1.QueryResolveResponse // DIDResolveResponse is the response type for the DID.Resolve RPC method.
|
||||
DWNParamsRequest = dwnv1.QueryParamsRequest // DWNParamsRequest is the request type for the DWN.Params RPC method.
|
||||
DWNParamsResponse = dwnv1.QueryParamsResponse // DWNParamsResponse is the response type for the DWN.Params RPC method.
|
||||
SVCParamsRequest = svcv1.QueryParamsRequest // SVCParamsRequest is the request type for the SVC.Params RPC method.
|
||||
SVCParamsResponse = svcv1.QueryParamsResponse // SVCParamsResponse is the response type for the SVC.Params RPC method.
|
||||
)
|
||||
|
||||
func conn(addr string) (*grpc.ClientConn, error) {
|
||||
grpcConn, err := grpc.NewClient(addr, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return grpcConn, nil
|
||||
}
|
||||
|
||||
func NewBankClient(addr string) (bankv1beta1.QueryClient, error) {
|
||||
conn, err := conn(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bankv1beta1.NewQueryClient(conn), nil
|
||||
}
|
||||
|
||||
func NewDIDClient(addr string) (didv1.QueryClient, error) {
|
||||
conn, err := conn(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return didv1.NewQueryClient(conn), nil
|
||||
}
|
||||
|
||||
func NewDWNClient(addr string) (dwnv1.QueryClient, error) {
|
||||
conn, err := conn(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dwnv1.NewQueryClient(conn), nil
|
||||
}
|
||||
|
||||
func NewNodeClient(addr string) (nodev1beta1.ServiceClient, error) {
|
||||
conn, err := conn(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nodev1beta1.NewServiceClient(conn), nil
|
||||
}
|
||||
|
||||
func NewSVCClient(addr string) (svcv1.QueryClient, error) {
|
||||
conn, err := conn(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return svcv1.NewQueryClient(conn), nil
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
// CookieKey is a type alias for string.
|
||||
type CookieKey string
|
||||
|
||||
const (
|
||||
// SessionID is the key for the session ID cookie.
|
||||
SessionID CookieKey = "session.id"
|
||||
|
||||
// SessionChallenge is the key for the session challenge cookie.
|
||||
SessionChallenge CookieKey = "session.challenge"
|
||||
|
||||
// SessionRole is the key for the session role cookie.
|
||||
SessionRole CookieKey = "session.role"
|
||||
|
||||
// SonrAddress is the key for the Sonr address cookie.
|
||||
SonrAddress CookieKey = "sonr.address"
|
||||
|
||||
// SonrDID is the key for the Sonr DID cookie.
|
||||
SonrDID CookieKey = "sonr.did"
|
||||
|
||||
// UserAvatar is the key for the User Avatar cookie.
|
||||
UserAvatar CookieKey = "user.avatar"
|
||||
|
||||
// UserHandle is the key for the User Handle cookie.
|
||||
UserHandle CookieKey = "user.handle"
|
||||
|
||||
// UserName is the key for the User Name cookie.
|
||||
UserName CookieKey = "user.full_name"
|
||||
|
||||
// VaultAddress is the key for the Vault address cookie.
|
||||
VaultAddress CookieKey = "vault.address"
|
||||
|
||||
// VaultCID is the key for the Vault CID cookie.
|
||||
VaultCID CookieKey = "vault.cid"
|
||||
|
||||
// VaultSchema is the key for the Vault schema cookie.
|
||||
VaultSchema CookieKey = "vault.schema"
|
||||
)
|
||||
|
||||
// String returns the string representation of the CookieKey.
|
||||
func (c CookieKey) String() string {
|
||||
return string(c)
|
||||
}
|
||||
|
||||
// ╭───────────────────────────────────────────────────────────╮
|
||||
// │ Utility Methods │
|
||||
// ╰───────────────────────────────────────────────────────────╯
|
||||
|
||||
func CookieExists(c echo.Context, key CookieKey) bool {
|
||||
ck, err := c.Cookie(key.String())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return ck != nil
|
||||
}
|
||||
|
||||
func ReadCookie(c echo.Context, key CookieKey) (string, error) {
|
||||
cookie, err := c.Cookie(key.String())
|
||||
if err != nil {
|
||||
// Cookie not found or other error
|
||||
return "", err
|
||||
}
|
||||
if cookie == nil || cookie.Value == "" {
|
||||
// Cookie is empty
|
||||
return "", http.ErrNoCookie
|
||||
}
|
||||
return cookie.Value, nil
|
||||
}
|
||||
|
||||
func ReadCookieBytes(c echo.Context, key CookieKey) ([]byte, error) {
|
||||
cookie, err := c.Cookie(key.String())
|
||||
if err != nil {
|
||||
// Cookie not found or other error
|
||||
return nil, err
|
||||
}
|
||||
if cookie == nil || cookie.Value == "" {
|
||||
// Cookie is empty
|
||||
return nil, http.ErrNoCookie
|
||||
}
|
||||
return base64.RawURLEncoding.DecodeString(cookie.Value)
|
||||
}
|
||||
|
||||
func ReadCookieUnsafe(c echo.Context, key CookieKey) string {
|
||||
ck, err := c.Cookie(key.String())
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return ck.Value
|
||||
}
|
||||
|
||||
func WriteCookie(c echo.Context, key CookieKey, value string) error {
|
||||
cookie := &http.Cookie{
|
||||
Name: key.String(),
|
||||
Value: value,
|
||||
Expires: time.Now().Add(24 * time.Hour),
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
// Add Secure and SameSite attributes as needed
|
||||
}
|
||||
c.SetCookie(cookie)
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteCookieBytes(c echo.Context, key CookieKey, value []byte) error {
|
||||
cookie := &http.Cookie{
|
||||
Name: key.String(),
|
||||
Value: base64.RawURLEncoding.EncodeToString(value),
|
||||
Expires: time.Now().Add(24 * time.Hour),
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
// Add Secure and SameSite attributes as needed
|
||||
}
|
||||
c.SetCookie(cookie)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package common
|
||||
|
||||
import "github.com/labstack/echo/v4"
|
||||
|
||||
type HeaderKey string
|
||||
|
||||
const (
|
||||
Authorization HeaderKey = "Authorization"
|
||||
|
||||
// User Agent
|
||||
Architecture HeaderKey = "Sec-CH-UA-Arch"
|
||||
Bitness HeaderKey = "Sec-CH-UA-Bitness"
|
||||
FullVersionList HeaderKey = "Sec-CH-UA-Full-Version-List"
|
||||
Mobile HeaderKey = "Sec-CH-UA-Mobile"
|
||||
Model HeaderKey = "Sec-CH-UA-Model"
|
||||
Platform HeaderKey = "Sec-CH-UA-Platform"
|
||||
PlatformVersion HeaderKey = "Sec-CH-UA-Platform-Version"
|
||||
UserAgent HeaderKey = "Sec-CH-UA"
|
||||
|
||||
// Sonr Injected
|
||||
SonrAPIURL HeaderKey = "X-Sonr-API"
|
||||
SonrgRPCURL HeaderKey = "X-Sonr-GRPC"
|
||||
SonrRPCURL HeaderKey = "X-Sonr-RPC"
|
||||
SonrWSURL HeaderKey = "X-Sonr-WS"
|
||||
)
|
||||
|
||||
func (h HeaderKey) String() string {
|
||||
return string(h)
|
||||
}
|
||||
|
||||
// ╭───────────────────────────────────────────────────────────╮
|
||||
// │ Utility Methods │
|
||||
// ╰───────────────────────────────────────────────────────────╯
|
||||
|
||||
func HeaderEquals(c echo.Context, key HeaderKey, value string) bool {
|
||||
return c.Response().Header().Get(key.String()) == value
|
||||
}
|
||||
|
||||
// HeaderExists returns true if the request has the header Key.
|
||||
func HeaderExists(c echo.Context, key HeaderKey) bool {
|
||||
return c.Response().Header().Get(key.String()) != ""
|
||||
}
|
||||
|
||||
// HeaderRead returns the header value for the Key.
|
||||
func HeaderRead(c echo.Context, key HeaderKey) string {
|
||||
return c.Response().Header().Get(key.String())
|
||||
}
|
||||
|
||||
// HeaderWrite sets the header value for the Key.
|
||||
func HeaderWrite(c echo.Context, key HeaderKey, value string) {
|
||||
c.Response().Header().Set(key.String(), value)
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/ipfs/boxo/files"
|
||||
"github.com/ipfs/boxo/path"
|
||||
"github.com/ipfs/kubo/client/rpc"
|
||||
"github.com/ipfs/kubo/core/coreiface/options"
|
||||
)
|
||||
|
||||
// IPFS represents a wrapper interface abstracting the localhost api
|
||||
type IPFS interface {
|
||||
Add(data []byte) (string, error)
|
||||
AddFile(file File) (string, error)
|
||||
AddFolder(folder Folder) (string, error)
|
||||
Exists(cid string) (bool, error)
|
||||
Get(cid string) ([]byte, error)
|
||||
IsPinned(ipns string) (bool, error)
|
||||
Ls(cid string) ([]string, error)
|
||||
Pin(cid string, name string) error
|
||||
Unpin(cid string) error
|
||||
}
|
||||
|
||||
type File interface {
|
||||
files.File
|
||||
Name() string
|
||||
}
|
||||
|
||||
func NewFileMap(vs []File) map[string]files.Node {
|
||||
m := make(map[string]files.Node)
|
||||
for _, f := range vs {
|
||||
m[f.Name()] = f
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
type client struct {
|
||||
api *rpc.HttpApi
|
||||
}
|
||||
|
||||
func NewIPFS() (IPFS, error) {
|
||||
api, err := rpc.NewLocalApi()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &client{api: api}, nil
|
||||
}
|
||||
|
||||
func (c *client) Add(data []byte) (string, error) {
|
||||
file := files.NewBytesFile(data)
|
||||
cidFile, err := c.api.Unixfs().Add(context.Background(), file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return cidFile.String(), nil
|
||||
}
|
||||
|
||||
func (c *client) Get(cid string) ([]byte, error) {
|
||||
p, err := path.NewPath(cid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node, err := c.api.Unixfs().Get(context.Background(), p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
file, ok := node.(files.File)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected node type: %T", node)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if _, err := io.Copy(buf, file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (c *client) IsPinned(ipns string) (bool, error) {
|
||||
_, err := c.api.Name().Resolve(context.Background(), ipns)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (c *client) Exists(cid string) (bool, error) {
|
||||
p, err := path.NewPath(cid)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = c.api.Block().Stat(context.Background(), p)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (c *client) Pin(cid string, name string) error {
|
||||
p, err := path.NewPath(cid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.api.Pin().Add(context.Background(), p, options.Pin.Name(name))
|
||||
}
|
||||
|
||||
func (c *client) Unpin(cid string) error {
|
||||
p, err := path.NewPath(cid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.api.Pin().Rm(context.Background(), p)
|
||||
}
|
||||
|
||||
func (c *client) Ls(cid string) ([]string, error) {
|
||||
p, err := path.NewPath(cid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node, err := c.api.Unixfs().Ls(context.Background(), p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var files []string
|
||||
for entry := range node {
|
||||
files = append(files, entry.Name)
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/boxo/files"
|
||||
)
|
||||
|
||||
type file struct {
|
||||
files.File
|
||||
name string
|
||||
}
|
||||
|
||||
func (f *file) Name() string {
|
||||
return f.name
|
||||
}
|
||||
|
||||
func NewFile(name string, data []byte) File {
|
||||
return &file{File: files.NewBytesFile(data), name: name}
|
||||
}
|
||||
|
||||
func (c *client) AddFile(file File) (string, error) {
|
||||
cidFile, err := c.api.Unixfs().Add(context.Background(), file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return cidFile.String(), nil
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/boxo/files"
|
||||
)
|
||||
|
||||
type Folder = files.Directory
|
||||
|
||||
func NewFolder(fs ...File) Folder {
|
||||
return files.NewMapDirectory(NewFileMap(fs))
|
||||
}
|
||||
|
||||
func (c *client) AddFolder(folder Folder) (string, error) {
|
||||
cidFile, err := c.api.Unixfs().Add(context.Background(), folder)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return cidFile.String(), nil
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/onsonr/sonr/internal/crypto/keys"
|
||||
"github.com/onsonr/sonr/internal/crypto/ucan"
|
||||
)
|
||||
|
||||
type IPFSTokenStore interface {
|
||||
ucan.TokenStore
|
||||
ResolveCIDBytes(ctx context.Context, id cid.Cid) ([]byte, error)
|
||||
ResolveDIDKey(ctx context.Context, did string) (keys.DID, error)
|
||||
}
|
||||
|
||||
// ipfsUCANStore is a token store that uses IPFS to store tokens. It uses the memory store as a cache
|
||||
// for CID strings to be used as keys for retrieving tokens.
|
||||
type ipfsUCANStore struct {
|
||||
sync.Mutex
|
||||
ipfs IPFS
|
||||
cache map[string]string
|
||||
}
|
||||
|
||||
// NewUCANStore creates a new IPFS-backed token store
|
||||
func NewUCANStore(ipfsClient IPFS) IPFSTokenStore {
|
||||
return &ipfsUCANStore{
|
||||
ipfs: ipfsClient,
|
||||
cache: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func (st *ipfsUCANStore) PutToken(ctx context.Context, key string, raw string) error {
|
||||
// Validate token format
|
||||
p := &jwt.Parser{
|
||||
UseJSONNumber: true,
|
||||
SkipClaimsValidation: false,
|
||||
}
|
||||
if _, _, err := p.ParseUnverified(raw, jwt.MapClaims{}); err != nil {
|
||||
return fmt.Errorf("%w: %s", ucan.ErrInvalidToken, err)
|
||||
}
|
||||
|
||||
// Store token in IPFS
|
||||
cid, err := st.ipfs.Add([]byte(raw))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to store token in IPFS: %w", err)
|
||||
}
|
||||
|
||||
// Update cache
|
||||
st.Lock()
|
||||
defer st.Unlock()
|
||||
st.cache[key] = cid
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *ipfsUCANStore) RawToken(ctx context.Context, key string) (string, error) {
|
||||
st.Lock()
|
||||
cid, exists := st.cache[key]
|
||||
st.Unlock()
|
||||
|
||||
if !exists {
|
||||
return "", ucan.ErrTokenNotFound
|
||||
}
|
||||
|
||||
// Retrieve token from IPFS
|
||||
data, err := st.ipfs.Get(cid)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve token from IPFS: %w", err)
|
||||
}
|
||||
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func (st *ipfsUCANStore) DeleteToken(ctx context.Context, key string) error {
|
||||
st.Lock()
|
||||
defer st.Unlock()
|
||||
|
||||
cid, exists := st.cache[key]
|
||||
if !exists {
|
||||
return ucan.ErrTokenNotFound
|
||||
}
|
||||
|
||||
// Unpin from IPFS
|
||||
if err := st.ipfs.Unpin(cid); err != nil {
|
||||
return fmt.Errorf("failed to unpin token from IPFS: %w", err)
|
||||
}
|
||||
|
||||
delete(st.cache, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *ipfsUCANStore) ListTokens(ctx context.Context, offset, limit int) ([]ucan.RawToken, error) {
|
||||
st.Lock()
|
||||
defer st.Unlock()
|
||||
|
||||
tokens := make(ucan.RawTokens, 0, len(st.cache))
|
||||
for key, cid := range st.cache {
|
||||
data, err := st.ipfs.Get(cid)
|
||||
if err != nil {
|
||||
continue // Skip invalid tokens
|
||||
}
|
||||
tokens = append(tokens, ucan.RawToken{
|
||||
Key: key,
|
||||
Raw: string(data),
|
||||
})
|
||||
}
|
||||
|
||||
// Sort tokens
|
||||
sort.Sort(tokens)
|
||||
|
||||
// Apply pagination
|
||||
if offset >= len(tokens) {
|
||||
return []ucan.RawToken{}, nil
|
||||
}
|
||||
|
||||
end := offset + limit
|
||||
if end > len(tokens) || limit <= 0 {
|
||||
end = len(tokens)
|
||||
}
|
||||
|
||||
return tokens[offset:end], nil
|
||||
}
|
||||
|
||||
func (st *ipfsUCANStore) ResolveCIDBytes(ctx context.Context, id cid.Cid) ([]byte, error) {
|
||||
data, err := st.ipfs.Get(id.String())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to resolve CID bytes: %w", err)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (st *ipfsUCANStore) ResolveDIDKey(ctx context.Context, did string) (keys.DID, error) {
|
||||
id, err := keys.Parse(did)
|
||||
if err != nil {
|
||||
return keys.DID{}, fmt.Errorf("failed to parse DID: %w", err)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
Reference in New Issue
Block a user