mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
refactor: move gateway and vault components to new locations
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
)
|
||||
|
||||
func (c *GatewayContext) NewChallenge() string {
|
||||
chal, _ := protocol.CreateChallenge()
|
||||
chalStr := chal.String()
|
||||
return chalStr
|
||||
}
|
||||
|
||||
func (cc *GatewayContext) ListCredentials(handle string) ([]*CredentialDescriptor, error) {
|
||||
creds, err := cc.GetCredentialsByHandle(bgCtx(), handle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return CredentialArrayToDescriptors(creds), nil
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/medama-io/go-useragent"
|
||||
"github.com/onsonr/sonr/internal/crypto/mpc"
|
||||
"github.com/onsonr/sonr/internal/common"
|
||||
"github.com/onsonr/sonr/internal/config/hway"
|
||||
hwayorm "github.com/onsonr/sonr/internal/database/hwayorm"
|
||||
)
|
||||
|
||||
type GatewayContext struct {
|
||||
echo.Context
|
||||
hwayorm.Querier
|
||||
id string
|
||||
ipfsClient common.IPFS
|
||||
agent useragent.UserAgent
|
||||
tokenStore common.IPFSTokenStore
|
||||
stagedEnclaves map[string]mpc.Enclave
|
||||
grpcAddr string
|
||||
turnstileSiteKey string
|
||||
}
|
||||
|
||||
func GetGateway(c echo.Context) (*GatewayContext, error) {
|
||||
cc, ok := c.(*GatewayContext)
|
||||
if !ok {
|
||||
return nil, echo.NewHTTPError(http.StatusInternalServerError, "Gateway Context not found")
|
||||
}
|
||||
return cc, nil
|
||||
}
|
||||
|
||||
func UseGateway(env hway.Hway, ipc common.IPFS, db *hwayorm.Queries) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
ua := useragent.NewParser()
|
||||
ctx := &GatewayContext{
|
||||
Context: c,
|
||||
Querier: db,
|
||||
ipfsClient: ipc,
|
||||
agent: ua.Parse(c.Request().UserAgent()),
|
||||
grpcAddr: env.GetSonrGrpcUrl(),
|
||||
tokenStore: common.NewUCANStore(ipc),
|
||||
turnstileSiteKey: env.GetTurnstileSiteKey(),
|
||||
}
|
||||
return next(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BG() gocontext.Context {
|
||||
ctx := gocontext.Background()
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (cc *GatewayContext) ReadCookie(k common.CookieKey) string {
|
||||
return common.ReadCookieUnsafe(cc.Context, k)
|
||||
}
|
||||
|
||||
func (cc *GatewayContext) WriteCookie(k common.CookieKey, v string) {
|
||||
common.WriteCookie(cc.Context, k, v)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
hwayorm "github.com/onsonr/sonr/internal/database/hwayorm"
|
||||
)
|
||||
|
||||
func UpdateProfile(c echo.Context) (*hwayorm.Profile, error) {
|
||||
ctx, ok := c.(*GatewayContext)
|
||||
if !ok {
|
||||
return nil, echo.NewHTTPError(http.StatusInternalServerError, "Profile Context not found")
|
||||
}
|
||||
address := c.FormValue("address")
|
||||
handle := c.FormValue("handle")
|
||||
name := c.FormValue("name")
|
||||
profile, err := ctx.UpdateProfile(bgCtx(), hwayorm.UpdateProfileParams{
|
||||
Address: address,
|
||||
Handle: handle,
|
||||
Name: name,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return profile, nil
|
||||
}
|
||||
|
||||
func ReadProfile(c echo.Context) (*hwayorm.Profile, error) {
|
||||
ctx, ok := c.(*GatewayContext)
|
||||
if !ok {
|
||||
return nil, echo.NewHTTPError(http.StatusInternalServerError, "Profile Context not found")
|
||||
}
|
||||
handle := c.Param("handle")
|
||||
profile, err := ctx.GetProfileByHandle(bgCtx(), handle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return profile, nil
|
||||
}
|
||||
|
||||
func DeleteProfile(c echo.Context) error {
|
||||
ctx, ok := c.(*GatewayContext)
|
||||
if !ok {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Profile Context not found")
|
||||
}
|
||||
address := c.Param("address")
|
||||
err := ctx.SoftDeleteProfile(bgCtx(), address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/onsonr/sonr/gateway/views"
|
||||
)
|
||||
|
||||
func Render(c echo.Context, cmp templ.Component) error {
|
||||
// Create a buffer to store the rendered HTML
|
||||
buf := &bytes.Buffer{}
|
||||
// Render the component to the buffer
|
||||
err := cmp.Render(c.Request().Context(), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the content type
|
||||
c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTML)
|
||||
|
||||
// Write the buffered content to the response
|
||||
_, err = c.Response().Write(buf.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Response().WriteHeader(200)
|
||||
return nil
|
||||
}
|
||||
|
||||
func RenderError(c echo.Context, err error) error {
|
||||
return Render(c, views.ErrorView(err.Error()))
|
||||
}
|
||||
|
||||
func RenderInitial(c echo.Context) error {
|
||||
return Render(c, views.InitialView())
|
||||
}
|
||||
|
||||
func RenderLoading(c echo.Context) error {
|
||||
return Render(c, views.LoadingView())
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/onsonr/sonr/internal/common"
|
||||
)
|
||||
|
||||
// ParamsBank returns the bank params
|
||||
func (cc *GatewayContext) ParamsBank() (*common.BankParamsResponse, error) {
|
||||
cl, err := common.NewBankClient(cc.grpcAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := cl.Params(bgCtx(), &common.BankParamsRequest{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ParamsDID returns the DID params
|
||||
func (cc *GatewayContext) ParamsDID() (*common.DIDParamsResponse, error) {
|
||||
cl, err := common.NewDIDClient(cc.grpcAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := cl.Params(bgCtx(), &common.DIDParamsRequest{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ParamsDWN returns the DWN params
|
||||
func (cc *GatewayContext) ParamsDWN() (*common.DWNParamsResponse, error) {
|
||||
cl, err := common.NewDWNClient(cc.grpcAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := cl.Params(bgCtx(), &common.DWNParamsRequest{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ParamsSVC returns the SVC params
|
||||
func (cc *GatewayContext) ParamsSVC() (*common.SVCParamsResponse, error) {
|
||||
cl, err := common.NewSVCClient(cc.grpcAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := cl.Params(bgCtx(), &common.SVCParamsRequest{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// StatusBlock returns the current block
|
||||
func (cc *GatewayContext) StatusBlock() string {
|
||||
qc, err := common.NewNodeClient(cc.grpcAddr)
|
||||
if err != nil {
|
||||
return "-1"
|
||||
}
|
||||
resp, err := qc.Status(bgCtx(), &common.StatusRequest{})
|
||||
if err != nil {
|
||||
return "-1"
|
||||
}
|
||||
return fmt.Sprintf("%d", resp.GetHeight())
|
||||
}
|
||||
|
||||
// StatusNode returns the node status
|
||||
func (cc *GatewayContext) StatusNode() (*common.StatusResponse, error) {
|
||||
cl, err := common.NewNodeClient(cc.grpcAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := cl.Status(bgCtx(), &common.StatusRequest{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// TxBroadcast broadcasts a transaction to the network
|
||||
func (cc *GatewayContext) TxBroadcast() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxEncode encodes a transaction
|
||||
func (cc *GatewayContext) TxEncode() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxDecode decodes a transaction
|
||||
func (cc *GatewayContext) TxDecode() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxSimulate simulates a transaction on the network
|
||||
func (cc *GatewayContext) TxSimulate() error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/onsonr/sonr/internal/common"
|
||||
"github.com/segmentio/ksuid"
|
||||
"lukechampine.com/blake3"
|
||||
)
|
||||
|
||||
func NewSession(c echo.Context) error {
|
||||
cc, ok := c.(*GatewayContext)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
baseSessionCreateParams := BaseSessionCreateParams(cc)
|
||||
cc.id = baseSessionCreateParams.ID
|
||||
if _, err := cc.CreateSession(bgCtx(), baseSessionCreateParams); err != nil {
|
||||
return err
|
||||
}
|
||||
// Set Cookie
|
||||
if err := common.WriteCookie(c, common.SessionID, cc.id); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Uses blake3 to hash the sessionID to generate a nonce of length 12 bytes
|
||||
func GetNonce(sessionID string) ([]byte, error) {
|
||||
hash := blake3.New(32, nil)
|
||||
_, err := hash.Write([]byte(sessionID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Read the hash into a byte slice
|
||||
nonce := make([]byte, 12)
|
||||
_, err = hash.Write(nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nonce, nil
|
||||
}
|
||||
|
||||
// ForbiddenDevice returns true if the device is unavailable
|
||||
func ForbiddenDevice(c echo.Context) bool {
|
||||
cc, ok := c.(*GatewayContext)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
return cc.agent.IsBot() || cc.agent.IsTV()
|
||||
}
|
||||
|
||||
func GetOrigin(c echo.Context) string {
|
||||
return c.Request().Host
|
||||
}
|
||||
|
||||
func GetSessionID(c echo.Context) string {
|
||||
// Check from context
|
||||
cc, ok := c.(*GatewayContext)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
// check from cookie
|
||||
if cc.id == "" {
|
||||
if ok := common.CookieExists(c, common.SessionID); !ok {
|
||||
return ""
|
||||
}
|
||||
cc.id = common.ReadCookieUnsafe(c, common.SessionID)
|
||||
}
|
||||
return cc.id
|
||||
}
|
||||
|
||||
func GetAuthChallenge(c echo.Context) string {
|
||||
cc, ok := c.(*GatewayContext)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
s, err := cc.GetChallengeBySessionID(bgCtx(), cc.id)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func GetProfileHandle(c echo.Context) string {
|
||||
// First check for the cookie
|
||||
handle := common.ReadCookieUnsafe(c, common.UserHandle)
|
||||
if handle != "" {
|
||||
return handle
|
||||
}
|
||||
|
||||
// Then check the session
|
||||
cc, ok := c.(*GatewayContext)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
s, err := cc.GetSessionByID(bgCtx(), cc.id)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
profile, err := cc.GetProfileByID(bgCtx(), s.ProfileID)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return profile.Handle
|
||||
}
|
||||
|
||||
//
|
||||
// func GetHumanVerificationNumbers(c echo.Context) (int64, int64) {
|
||||
// cc, ok := c.(*GatewayContext)
|
||||
// if !ok {
|
||||
// return 0, 0
|
||||
// }
|
||||
// s, err := cc.dbq.GetHumanVerificationNumbers(bgCtx(), cc.id)
|
||||
// if err != nil {
|
||||
// return 0, 0
|
||||
// }
|
||||
// return s.IsHumanFirst, s.IsHumanLast
|
||||
// }
|
||||
|
||||
// utility function to get a context
|
||||
func bgCtx() gocontext.Context {
|
||||
ctx := gocontext.Background()
|
||||
return ctx
|
||||
}
|
||||
|
||||
func getOrCreateSessionID(c echo.Context) string {
|
||||
if ok := common.CookieExists(c, common.SessionID); !ok {
|
||||
sessionID := ksuid.New().String()
|
||||
common.WriteCookie(c, common.SessionID, sessionID)
|
||||
return sessionID
|
||||
}
|
||||
|
||||
sessionID, err := common.ReadCookie(c, common.SessionID)
|
||||
if err != nil {
|
||||
sessionID = ksuid.New().String()
|
||||
common.WriteCookie(c, common.SessionID, sessionID)
|
||||
}
|
||||
return sessionID
|
||||
}
|
||||
|
||||
func boolToInt64(b bool) int64 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/medama-io/go-useragent"
|
||||
hwayorm "github.com/onsonr/sonr/internal/database/hwayorm"
|
||||
)
|
||||
|
||||
// Define the credential structure matching our frontend data
|
||||
type CredentialDescriptor struct {
|
||||
ID string `json:"id"`
|
||||
RawID string `json:"rawId"`
|
||||
Type string `json:"type"`
|
||||
AuthenticatorAttachment string `json:"authenticatorAttachment"`
|
||||
Transports string `json:"transports"`
|
||||
ClientExtensionResults map[string]string `json:"clientExtensionResults"`
|
||||
Response struct {
|
||||
AttestationObject string `json:"attestationObject"`
|
||||
ClientDataJSON string `json:"clientDataJSON"`
|
||||
} `json:"response"`
|
||||
}
|
||||
|
||||
func (c *CredentialDescriptor) ToModel(handle, origin string) *hwayorm.Credential {
|
||||
return &hwayorm.Credential{
|
||||
Handle: handle,
|
||||
Origin: origin,
|
||||
CredentialID: c.ID,
|
||||
Type: c.Type,
|
||||
Transports: c.Transports,
|
||||
AuthenticatorAttachment: c.AuthenticatorAttachment,
|
||||
}
|
||||
}
|
||||
|
||||
func CredentialArrayToDescriptors(credentials []*hwayorm.Credential) []*CredentialDescriptor {
|
||||
var descriptors []*CredentialDescriptor
|
||||
for _, cred := range credentials {
|
||||
cd := &CredentialDescriptor{
|
||||
ID: cred.CredentialID,
|
||||
RawID: cred.CredentialID,
|
||||
Type: cred.Type,
|
||||
AuthenticatorAttachment: cred.AuthenticatorAttachment,
|
||||
Transports: cred.Transports,
|
||||
}
|
||||
descriptors = append(descriptors, cd)
|
||||
}
|
||||
return descriptors
|
||||
}
|
||||
|
||||
func BaseSessionCreateParams(e echo.Context) hwayorm.CreateSessionParams {
|
||||
// f := rand.Intn(5) + 1
|
||||
// l := rand.Intn(4) + 1
|
||||
challenge, _ := protocol.CreateChallenge()
|
||||
id := getOrCreateSessionID(e)
|
||||
ua := useragent.NewParser()
|
||||
s := ua.Parse(e.Request().UserAgent())
|
||||
|
||||
return hwayorm.CreateSessionParams{
|
||||
ID: id,
|
||||
BrowserName: s.GetBrowser(),
|
||||
BrowserVersion: s.GetMajorVersion(),
|
||||
ClientIpaddr: e.RealIP(),
|
||||
Platform: s.GetOS(),
|
||||
IsMobile: s.IsMobile(),
|
||||
IsTablet: s.IsTablet(),
|
||||
IsDesktop: s.IsDesktop(),
|
||||
IsBot: s.IsBot(),
|
||||
IsTv: s.IsTV(),
|
||||
// IsHumanFirst: int64(f),
|
||||
// IsHumanLast: int64(l),
|
||||
Challenge: challenge.String(),
|
||||
}
|
||||
}
|
||||
|
||||
// ╭───────────────────────────────────────────────────────────╮
|
||||
// │ Create Passkey (/register/passkey) │
|
||||
// ╰───────────────────────────────────────────────────────────╯
|
||||
|
||||
// CreatePasskeyParams represents the parameters for creating a passkey
|
||||
type CreatePasskeyParams struct {
|
||||
Address string
|
||||
Handle string
|
||||
Name string
|
||||
Challenge string
|
||||
CreationBlock string
|
||||
}
|
||||
|
||||
// ╭───────────────────────────────────────────────────────────╮
|
||||
// │ Create Profile (/register/profile) │
|
||||
// ╰───────────────────────────────────────────────────────────╯
|
||||
|
||||
// CreateProfileParams represents the parameters for creating a profile
|
||||
type CreateProfileParams struct {
|
||||
TurnstileSiteKey string
|
||||
FirstNumber int
|
||||
LastNumber int
|
||||
}
|
||||
|
||||
// Sum returns the sum of the first and last number
|
||||
func (d CreateProfileParams) Sum() int {
|
||||
return d.FirstNumber + d.LastNumber
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"github.com/onsonr/sonr/internal/crypto/mpc"
|
||||
"github.com/onsonr/sonr/internal/common"
|
||||
"lukechampine.com/blake3"
|
||||
)
|
||||
|
||||
func (cc *GatewayContext) Spawn(handle, origin string) (*CreatePasskeyParams, error) {
|
||||
challenge := GetAuthChallenge(cc)
|
||||
sid := GetSessionID(cc)
|
||||
nonce, err := calcNonce(sid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encl, err := mpc.GenEnclave(nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cc.stagedEnclaves[sid] = encl
|
||||
common.WriteCookie(cc, common.SonrAddress, encl.Address())
|
||||
return &CreatePasskeyParams{
|
||||
Address: encl.Address(),
|
||||
Handle: handle,
|
||||
Name: origin,
|
||||
Challenge: challenge,
|
||||
CreationBlock: cc.StatusBlock(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Uses blake3 to hash the sessionID to generate a nonce of length 12 bytes
|
||||
func calcNonce(sessionID string) ([]byte, error) {
|
||||
hash := blake3.New(32, nil)
|
||||
_, err := hash.Write([]byte(sessionID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Read the hash into a byte slice
|
||||
nonce := make([]byte, 12)
|
||||
_, err = hash.Write(nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nonce, nil
|
||||
}
|
||||
Reference in New Issue
Block a user