mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-03 09:51:39 +00:00
449 lines
9.9 KiB
Go
449 lines
9.9 KiB
Go
//go:build (linux || darwin || windows || freebsd || illumos) && !sqlite3_nosys
|
|
|
|
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
"github.com/onsonr/hway/crypto"
|
|
"github.com/onsonr/hway/crypto/secret"
|
|
|
|
_ "github.com/ncruces/go-sqlite3/driver"
|
|
_ "github.com/ncruces/go-sqlite3/embed"
|
|
)
|
|
|
|
const kVaultDBFileName = "file:demo.db?_pragma=busy_timeout(10000)"
|
|
|
|
type Database interface {
|
|
ExistsCredential(did string) bool
|
|
ExistsProfile(did string) bool
|
|
ExistsWallet(did string) bool
|
|
|
|
GetCredential(did string) (*Credential, error)
|
|
GetProfile(did string) (*Profile, error)
|
|
GetWallet(did string) (*Wallet, error)
|
|
|
|
InsertCredentials(credentials ...*Credential) error
|
|
InsertProfiles(profiles ...*Profile) error
|
|
InsertWallets(wallets ...*Wallet) error
|
|
|
|
ListCredentials() ([]*Credential, error)
|
|
ListProfiles() ([]*Profile, error)
|
|
ListWallets() ([]*Wallet, error)
|
|
}
|
|
|
|
type Credential struct {
|
|
Transport string
|
|
Origin string
|
|
Controller string
|
|
DID string
|
|
DisplayName string
|
|
AttestationType string
|
|
Attachment string
|
|
AAGUID []byte
|
|
PublicKey []byte
|
|
CredentialID []byte
|
|
ID int64
|
|
SignCount uint32
|
|
BackupEligible bool
|
|
BackupState bool
|
|
UserVerified bool
|
|
UserPresent bool
|
|
}
|
|
|
|
type Profile struct {
|
|
DID string
|
|
DisplayName string
|
|
Name string
|
|
Origin string
|
|
Controller string
|
|
ID int64
|
|
}
|
|
|
|
type Wallet struct {
|
|
Address string
|
|
Controller string
|
|
Name string
|
|
ChainID string
|
|
Network string
|
|
Label string
|
|
DID string
|
|
PublicKey []byte
|
|
ID int64
|
|
Index int
|
|
CoinType int64
|
|
}
|
|
|
|
func seedDB() (Database, error) {
|
|
db, err := sql.Open("sqlite", kVaultDBFileName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Create tables
|
|
_, err = db.Exec(`
|
|
CREATE TABLE IF NOT EXISTS credentials (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
display_name TEXT,
|
|
origin TEXT,
|
|
controller TEXT,
|
|
attestation_type TEXT,
|
|
did TEXT UNIQUE,
|
|
credential_id BLOB,
|
|
public_key BLOB,
|
|
transport TEXT,
|
|
user_present BOOLEAN,
|
|
user_verified BOOLEAN,
|
|
backup_eligible BOOLEAN,
|
|
backup_state BOOLEAN,
|
|
aaguid BLOB,
|
|
sign_count INTEGER,
|
|
attachment TEXT
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS profiles (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
did TEXT UNIQUE,
|
|
display_name TEXT,
|
|
name TEXT,
|
|
origin TEXT,
|
|
controller TEXT
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS wallets (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
address TEXT,
|
|
controller TEXT,
|
|
name TEXT,
|
|
chain_id TEXT,
|
|
network TEXT,
|
|
label TEXT,
|
|
did TEXT UNIQUE,
|
|
public_key BLOB,
|
|
index_num INTEGER,
|
|
coin_type INTEGER
|
|
);
|
|
`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &embedDB{DB: db}, nil
|
|
}
|
|
|
|
type embedDB struct {
|
|
DB *sql.DB
|
|
}
|
|
|
|
func (db *embedDB) GetCredential(did string) (*Credential, error) {
|
|
credential := new(Credential)
|
|
err := db.DB.QueryRow("SELECT * FROM credentials WHERE did = ?", did).Scan(
|
|
&credential.ID, &credential.DisplayName, &credential.Origin, &credential.Controller,
|
|
&credential.AttestationType, &credential.DID, &credential.CredentialID, &credential.PublicKey,
|
|
&credential.Transport, &credential.UserPresent, &credential.UserVerified,
|
|
&credential.BackupEligible, &credential.BackupState, &credential.AAGUID,
|
|
&credential.SignCount, &credential.Attachment,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return credential, nil
|
|
}
|
|
|
|
func (db *embedDB) GetProfile(did string) (*Profile, error) {
|
|
profile := new(Profile)
|
|
err := db.DB.QueryRow("SELECT * FROM profiles WHERE did = ?", did).Scan(
|
|
&profile.ID, &profile.DID, &profile.DisplayName, &profile.Name,
|
|
&profile.Origin, &profile.Controller,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return profile, nil
|
|
}
|
|
|
|
func (db *embedDB) GetWallet(did string) (*Wallet, error) {
|
|
wallet := new(Wallet)
|
|
err := db.DB.QueryRow("SELECT * FROM wallets WHERE did = ?", did).Scan(
|
|
&wallet.ID, &wallet.Address, &wallet.Controller, &wallet.Name,
|
|
&wallet.ChainID, &wallet.Network, &wallet.Label, &wallet.DID,
|
|
&wallet.PublicKey, &wallet.Index, &wallet.CoinType,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return wallet, nil
|
|
}
|
|
|
|
func (db *embedDB) ExistsCredential(did string) bool {
|
|
var count int
|
|
db.DB.QueryRow("SELECT COUNT(*) FROM credentials WHERE did = ?", did).Scan(&count)
|
|
return count > 0
|
|
}
|
|
|
|
func (db *embedDB) ExistsProfile(did string) bool {
|
|
var count int
|
|
db.DB.QueryRow("SELECT COUNT(*) FROM profiles WHERE did = ?", did).Scan(&count)
|
|
return count > 0
|
|
}
|
|
|
|
func (db *embedDB) ExistsWallet(did string) bool {
|
|
var count int
|
|
db.DB.QueryRow("SELECT COUNT(*) FROM wallets WHERE did = ?", did).Scan(&count)
|
|
return count > 0
|
|
}
|
|
|
|
func (db *embedDB) InsertCredentials(credentials ...*Credential) error {
|
|
tx, err := db.DB.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
stmt, err := tx.Prepare(`
|
|
INSERT INTO credentials (
|
|
display_name, origin, controller, attestation_type, did, credential_id,
|
|
public_key, transport, user_present, user_verified, backup_eligible,
|
|
backup_state, aaguid, sign_count, attachment
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
for _, c := range credentials {
|
|
_, err = stmt.Exec(
|
|
c.DisplayName, c.Origin, c.Controller, c.AttestationType, c.DID, c.CredentialID,
|
|
c.PublicKey, c.Transport, c.UserPresent, c.UserVerified, c.BackupEligible,
|
|
c.BackupState, c.AAGUID, c.SignCount, c.Attachment,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
func (db *embedDB) InsertProfiles(profiles ...*Profile) error {
|
|
tx, err := db.DB.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
stmt, err := tx.Prepare(`
|
|
INSERT INTO profiles (did, display_name, name, origin, controller)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
`)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
for _, p := range profiles {
|
|
_, err = stmt.Exec(p.DID, p.DisplayName, p.Name, p.Origin, p.Controller)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
func (db *embedDB) InsertWallets(wallets ...*Wallet) error {
|
|
tx, err := db.DB.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
stmt, err := tx.Prepare(`
|
|
INSERT INTO wallets (
|
|
address, controller, name, chain_id, network, label, did,
|
|
public_key, index_num, coin_type
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
for _, w := range wallets {
|
|
_, err = stmt.Exec(
|
|
w.Address, w.Controller, w.Name, w.ChainID, w.Network, w.Label, w.DID,
|
|
w.PublicKey, w.Index, w.CoinType,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
func (db *embedDB) ListCredentials() ([]*Credential, error) {
|
|
rows, err := db.DB.Query("SELECT * FROM credentials")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var credentials []*Credential
|
|
for rows.Next() {
|
|
c := new(Credential)
|
|
err := rows.Scan(
|
|
&c.ID, &c.DisplayName, &c.Origin, &c.Controller, &c.AttestationType,
|
|
&c.DID, &c.CredentialID, &c.PublicKey, &c.Transport, &c.UserPresent,
|
|
&c.UserVerified, &c.BackupEligible, &c.BackupState, &c.AAGUID,
|
|
&c.SignCount, &c.Attachment,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
credentials = append(credentials, c)
|
|
}
|
|
return credentials, nil
|
|
}
|
|
|
|
func (db *embedDB) ListProfiles() ([]*Profile, error) {
|
|
rows, err := db.DB.Query("SELECT * FROM profiles")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var profiles []*Profile
|
|
for rows.Next() {
|
|
p := new(Profile)
|
|
err := rows.Scan(&p.ID, &p.DID, &p.DisplayName, &p.Name, &p.Origin, &p.Controller)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
profiles = append(profiles, p)
|
|
}
|
|
return profiles, nil
|
|
}
|
|
|
|
func (db *embedDB) ListWallets() ([]*Wallet, error) {
|
|
rows, err := db.DB.Query("SELECT * FROM wallets")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var wallets []*Wallet
|
|
for rows.Next() {
|
|
w := new(Wallet)
|
|
err := rows.Scan(
|
|
&w.ID, &w.Address, &w.Controller, &w.Name, &w.ChainID, &w.Network,
|
|
&w.Label, &w.DID, &w.PublicKey, &w.Index, &w.CoinType,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
wallets = append(wallets, w)
|
|
}
|
|
return wallets, nil
|
|
}
|
|
|
|
func (db *embedDB) WitnessCredential(publicKey crypto.PublicKey, did string) ([]byte, error) {
|
|
if !db.ExistsCredential(did) {
|
|
return nil, fmt.Errorf("credential with DID %s does not exist", did)
|
|
}
|
|
|
|
pk, err := secret.NewKey("credentials", publicKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
creds, err := db.ListCredentials()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
credIDStrs := make([]string, len(creds))
|
|
for i, c := range creds {
|
|
credIDStrs[i] = c.DID
|
|
}
|
|
|
|
acc, err := pk.CreateAccumulator(credIDStrs...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
witness, err := pk.CreateWitness(acc, did)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return witness.MarshalBinary()
|
|
}
|
|
|
|
func (db *embedDB) WitnessProfile(publicKey crypto.PublicKey, did string) ([]byte, error) {
|
|
if !db.ExistsProfile(did) {
|
|
return nil, fmt.Errorf("profile with DID %s does not exist", did)
|
|
}
|
|
|
|
pk, err := secret.NewKey("profiles", publicKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
profiles, err := db.ListProfiles()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
profileIDs := make([]string, len(profiles))
|
|
for i, p := range profiles {
|
|
profileIDs[i] = p.DID
|
|
}
|
|
|
|
acc, err := pk.CreateAccumulator(profileIDs...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
witness, err := pk.CreateWitness(acc, did)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return witness.MarshalBinary()
|
|
}
|
|
|
|
func (db *embedDB) WitnessWallet(publicKey crypto.PublicKey, did string) ([]byte, error) {
|
|
if !db.ExistsWallet(did) {
|
|
return nil, fmt.Errorf("wallet with DID %s does not exist", did)
|
|
}
|
|
|
|
pk, err := secret.NewKey("wallets", publicKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
wallets, err := db.ListWallets()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
walletIDs := make([]string, len(wallets))
|
|
for i, w := range wallets {
|
|
walletIDs[i] = w.DID
|
|
}
|
|
|
|
acc, err := pk.CreateAccumulator(walletIDs...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
witness, err := pk.CreateWitness(acc, did)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return witness.MarshalBinary()
|
|
}
|
|
|
|
func main() {}
|