add client table, ensure client id / public / private key

This commit is contained in:
sawka 2022-08-15 18:42:25 -07:00
parent 550fd89472
commit 8186e54cd2
3 changed files with 106 additions and 5 deletions

View File

@ -456,6 +456,12 @@ func main() {
fmt.Printf("[error] ensuring default session: %v\n", err)
return
}
userData, err := sstore.EnsureUserData(context.Background())
if err != nil {
fmt.Printf("[error] ensuring user data: %v\n", err)
return
}
fmt.Printf("userid = %s\n", userData.UserId)
err = remote.LoadRemotes(context.Background())
if err != nil {
fmt.Printf("[error] loading remotes: %v\n", err)

View File

@ -1,3 +1,9 @@
CREATE TABLE client (
userid varchar(36) NOT NULL,
userpublickeybytes blob NOT NULL,
userprivatekeybytes blob NOT NULL
);
CREATE TABLE session (
sessionid varchar(36) PRIMARY KEY,
name varchar(50) NOT NULL,

View File

@ -2,6 +2,10 @@ package sstore
import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"database/sql/driver"
"fmt"
"log"
@ -10,6 +14,7 @@ import (
"sync"
"time"
"github.com/google/uuid"
"github.com/jmoiron/sqlx"
"github.com/scripthaus-dev/mshell/pkg/base"
"github.com/scripthaus-dev/mshell/pkg/packet"
@ -29,11 +34,21 @@ const DefaultScreenWindowName = "w1"
const DefaultCwd = "~"
const CmdStatusRunning = "running"
const CmdStatusDetached = "detached"
const CmdStatusError = "error"
const CmdStatusDone = "done"
const CmdStatusHangup = "hangup"
const (
CmdStatusRunning = "running"
CmdStatusDetached = "detached"
CmdStatusError = "error"
CmdStatusDone = "done"
CmdStatusHangup = "hangup"
)
const (
ShareModeLocal = "local"
ShareModePrivate = "private"
ShareModeView = "view"
ShareModeShared = "shared"
ShareModeSharedView = "shared-view"
)
var globalDBLock = &sync.Mutex{}
var globalDB *sqlx.DB
@ -56,6 +71,14 @@ func GetDB(ctx context.Context) (*sqlx.DB, error) {
return globalDB, globalDBErr
}
type UserData struct {
UserId string `json:"userid"`
UserPrivateKeyBytes []byte `json:"-"`
UserPublicKeyBytes []byte `json:"-"`
UserPrivateKey *ecdsa.PrivateKey
UserPublicKey *ecdsa.PublicKey
}
type SessionType struct {
SessionId string `json:"sessionid"`
Name string `json:"name"`
@ -413,3 +436,69 @@ func EnsureDefaultSession(ctx context.Context) (*SessionType, error) {
}
return GetSessionByName(ctx, DefaultSessionName)
}
func createUserData(tx *TxWrap) error {
userId := uuid.New().String()
curve := elliptic.P384()
pkey, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
return fmt.Errorf("generating P-834 key: %w", err)
}
pkBytes, err := x509.MarshalECPrivateKey(pkey)
if err != nil {
return fmt.Errorf("marshaling (pkcs8) private key bytes: %w", err)
}
pubBytes, err := x509.MarshalPKIXPublicKey(&pkey.PublicKey)
if err != nil {
return fmt.Errorf("marshaling (pkix) public key bytes: %w", err)
}
query := `INSERT INTO client (userid, userpublickeybytes, userprivatekeybytes) VALUES (?, ?, ?)`
tx.ExecWrap(query, userId, pubBytes, pkBytes)
fmt.Printf("create new userid[%s] with public/private keypair\n", userId)
return nil
}
func EnsureUserData(ctx context.Context) (*UserData, error) {
var rtn UserData
err := WithTx(ctx, func(tx *TxWrap) error {
query := `SELECT count(*) FROM client`
count := tx.GetInt(query)
if count > 1 {
return fmt.Errorf("invalid client database, multiple (%d) rows in client table", count)
}
if count == 0 {
createErr := createUserData(tx)
if createErr != nil {
return createErr
}
}
found := tx.GetWrap(&rtn, "SELECT * FROM client")
if !found {
return fmt.Errorf("invalid client data")
}
return nil
})
if err != nil {
return nil, err
}
if rtn.UserId == "" {
return nil, fmt.Errorf("invalid client data (no userid)")
}
if len(rtn.UserPrivateKeyBytes) == 0 || len(rtn.UserPublicKeyBytes) == 0 {
return nil, fmt.Errorf("invalid client data (no public/private keypair)")
}
rtn.UserPrivateKey, err = x509.ParseECPrivateKey(rtn.UserPrivateKeyBytes)
if err != nil {
return nil, fmt.Errorf("invalid client data, cannot parse private key: %w", err)
}
pubKey, err := x509.ParsePKIXPublicKey(rtn.UserPublicKeyBytes)
if err != nil {
return nil, fmt.Errorf("invalid client data, cannot parse public key: %w", err)
}
var ok bool
rtn.UserPublicKey, ok = pubKey.(*ecdsa.PublicKey)
if !ok {
return nil, fmt.Errorf("invalid client data, wrong public key type: %T", pubKey)
}
return &rtn, nil
}