Permissions api (#1524)
* Add permissions api * Integrate permissions service * Reduce cyclomatic complexity of the MakeNode function
This commit is contained in:
parent
9a0502fa8f
commit
9723b64827
|
@ -571,7 +571,11 @@ func (b *StatusBackend) SelectAccount(walletAddress, chatAddress, password strin
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.startBrowsers(password)
|
||||
err = b.startBrowsers(password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.startPermissions(password)
|
||||
}
|
||||
|
||||
func (b *StatusBackend) startWallet(password string) error {
|
||||
|
@ -609,6 +613,22 @@ func (b *StatusBackend) startBrowsers(password string) error {
|
|||
return svc.StartDatabase(path, password)
|
||||
}
|
||||
|
||||
func (b *StatusBackend) startPermissions(password string) error {
|
||||
if !b.statusNode.Config().PermissionsConfig.Enabled {
|
||||
return nil
|
||||
}
|
||||
svc, err := b.statusNode.PermissionsService()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
account, err := b.accountManager.SelectedWalletAccount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := path.Join(b.statusNode.Config().DataDir, fmt.Sprintf("permissions-%x.sql", account.Address))
|
||||
return svc.StartDatabase(path, password)
|
||||
}
|
||||
|
||||
// SendDataNotification sends data push notifications to users.
|
||||
// dataPayloadJSON is a JSON string that looks like this:
|
||||
// {
|
||||
|
|
44
node/node.go
44
node/node.go
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/status-im/status-go/services/browsers"
|
||||
"github.com/status-im/status-go/services/incentivisation"
|
||||
"github.com/status-im/status-go/services/peer"
|
||||
"github.com/status-im/status-go/services/permissions"
|
||||
"github.com/status-im/status-go/services/personal"
|
||||
"github.com/status-im/status-go/services/shhext"
|
||||
"github.com/status-im/status-go/services/status"
|
||||
|
@ -49,6 +50,7 @@ var (
|
|||
ErrIncentivisationServiceRegistrationFailure = errors.New("failed to register the Incentivisation service")
|
||||
ErrWalletServiceRegistrationFailure = errors.New("failed to register the Wallet service")
|
||||
ErrBrowsersServiceRegistrationFailure = errors.New("failed to register the Browsers service")
|
||||
ErrPermissionsServiceRegistrationFailure = errors.New("failed to register the Permissions service")
|
||||
)
|
||||
|
||||
// All general log messages in this package should be routed through this logger.
|
||||
|
@ -80,14 +82,22 @@ func MakeNode(config *params.NodeConfig, db *leveldb.DB) (*node.Node, error) {
|
|||
return nil, fmt.Errorf(ErrNodeMakeFailureFormat, err.Error())
|
||||
}
|
||||
|
||||
err = activateServices(stack, config, db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stack, nil
|
||||
}
|
||||
|
||||
func activateServices(stack *node.Node, config *params.NodeConfig, db *leveldb.DB) error {
|
||||
// start Ethereum service if we are not expected to use an upstream server
|
||||
if !config.UpstreamConfig.Enabled {
|
||||
if err := activateLightEthService(stack, config); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", ErrLightEthRegistrationFailure, err)
|
||||
return fmt.Errorf("%v: %v", ErrLightEthRegistrationFailure, err)
|
||||
}
|
||||
} else {
|
||||
if config.LightEthConfig.Enabled {
|
||||
return nil, fmt.Errorf("%v: %v", ErrLightEthRegistrationFailureUpstreamEnabled, err)
|
||||
return ErrLightEthRegistrationFailureUpstreamEnabled
|
||||
}
|
||||
|
||||
logger.Info("LES protocol is disabled")
|
||||
|
@ -98,39 +108,43 @@ func MakeNode(config *params.NodeConfig, db *leveldb.DB) (*node.Node, error) {
|
|||
// upstream, we don't start any of these, so we need to start our own
|
||||
// implementation.
|
||||
if err := activatePersonalService(stack, config); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", ErrPersonalServiceRegistrationFailure, err)
|
||||
return fmt.Errorf("%v: %v", ErrPersonalServiceRegistrationFailure, err)
|
||||
}
|
||||
}
|
||||
|
||||
// start Whisper service.
|
||||
if err := activateShhService(stack, config, db); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", ErrWhisperServiceRegistrationFailure, err)
|
||||
return fmt.Errorf("%v: %v", ErrWhisperServiceRegistrationFailure, err)
|
||||
}
|
||||
|
||||
// start incentivisation service
|
||||
if err := activateIncentivisationService(stack, config); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", ErrIncentivisationServiceRegistrationFailure, err)
|
||||
return fmt.Errorf("%v: %v", ErrIncentivisationServiceRegistrationFailure, err)
|
||||
}
|
||||
|
||||
// start status service.
|
||||
if err := activateStatusService(stack, config); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", ErrStatusServiceRegistrationFailure, err)
|
||||
return fmt.Errorf("%v: %v", ErrStatusServiceRegistrationFailure, err)
|
||||
}
|
||||
|
||||
// start peer service
|
||||
if err := activatePeerService(stack); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", ErrPeerServiceRegistrationFailure, err)
|
||||
return fmt.Errorf("%v: %v", ErrPeerServiceRegistrationFailure, err)
|
||||
}
|
||||
|
||||
if err := activateWalletService(stack, config.WalletConfig); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", ErrWalletServiceRegistrationFailure, err)
|
||||
return fmt.Errorf("%v: %v", ErrWalletServiceRegistrationFailure, err)
|
||||
}
|
||||
|
||||
if err := activateBrowsersService(stack, config.BrowsersConfig); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", ErrBrowsersServiceRegistrationFailure, err)
|
||||
return fmt.Errorf("%v: %v", ErrBrowsersServiceRegistrationFailure, err)
|
||||
}
|
||||
|
||||
return stack, nil
|
||||
if err := activatePermissionsService(stack, config.PermissionsConfig); err != nil {
|
||||
return fmt.Errorf("%v: %v", ErrPermissionsServiceRegistrationFailure, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// newGethNodeConfig returns default stack configuration for mobile client node
|
||||
|
@ -301,6 +315,16 @@ func activateBrowsersService(stack *node.Node, config params.BrowsersConfig) err
|
|||
})
|
||||
}
|
||||
|
||||
func activatePermissionsService(stack *node.Node, config params.PermissionsConfig) error {
|
||||
if !config.Enabled {
|
||||
logger.Info("dapps permissions service is disabled")
|
||||
return nil
|
||||
}
|
||||
return stack.Register(func(*node.ServiceContext) (node.Service, error) {
|
||||
return permissions.NewService(), nil
|
||||
})
|
||||
}
|
||||
|
||||
func registerMailServer(whisperService *whisper.Whisper, config *params.WhisperConfig) (err error) {
|
||||
var mailServer mailserver.WMailServer
|
||||
whisperService.RegisterServer(&mailServer)
|
||||
|
|
|
@ -31,6 +31,7 @@ import (
|
|||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/browsers"
|
||||
"github.com/status-im/status-go/services/peer"
|
||||
"github.com/status-im/status-go/services/permissions"
|
||||
"github.com/status-im/status-go/services/shhext"
|
||||
"github.com/status-im/status-go/services/status"
|
||||
"github.com/status-im/status-go/services/wallet"
|
||||
|
@ -614,6 +615,17 @@ func (n *StatusNode) BrowsersService() (s *browsers.Service, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// PermissionsService returns browsers.Service instance if it was started.
|
||||
func (n *StatusNode) PermissionsService() (s *permissions.Service, err error) {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
err = n.gethService(&s)
|
||||
if err == node.ErrServiceUnknown {
|
||||
err = ErrServiceUnknown
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AccountManager exposes reference to node's accounts manager
|
||||
func (n *StatusNode) AccountManager() (*accounts.Manager, error) {
|
||||
n.mu.RLock()
|
||||
|
|
|
@ -349,6 +349,9 @@ type NodeConfig struct {
|
|||
// BrowsersConfig extra configuration for browsers.Service.
|
||||
BrowsersConfig BrowsersConfig
|
||||
|
||||
// PermissionsConfig extra configuration for permissions.Service.
|
||||
PermissionsConfig PermissionsConfig
|
||||
|
||||
// SwarmConfig extra configuration for Swarm and ENS
|
||||
SwarmConfig SwarmConfig `json:"SwarmConfig," validate:"structonly"`
|
||||
|
||||
|
@ -374,6 +377,11 @@ type BrowsersConfig struct {
|
|||
Enabled bool
|
||||
}
|
||||
|
||||
// PermissionsConfig extra configuration for permissions.Service.
|
||||
type PermissionsConfig struct {
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
// ShhextConfig defines options used by shhext service.
|
||||
type ShhextConfig struct {
|
||||
PFSEnabled bool
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
Dapps permissions service
|
||||
=========================
|
||||
|
||||
To enable:
|
||||
|
||||
```json
|
||||
{
|
||||
"PermissionsConfig": {
|
||||
"Enabled": true,
|
||||
},
|
||||
APIModules: "permissions"
|
||||
}
|
||||
```
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
#### permissions_addDappPermissions
|
||||
|
||||
Stores provided permissions for dapp. On update replaces previous version of the object.
|
||||
|
||||
```json
|
||||
{
|
||||
"dapp": "first",
|
||||
"permissions": [
|
||||
"r",
|
||||
"x"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### permissions_getDappPermissions
|
||||
|
||||
Returns all permissions for dapps. Order is not deterministic.
|
||||
|
||||
#### permissions_deleteDappPermissions
|
||||
|
||||
Delete dapp by a name.
|
|
@ -0,0 +1,41 @@
|
|||
package permissions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrServiceNotInitialized returned when permissions is not initialized/started,.
|
||||
ErrServiceNotInitialized = errors.New("permissions service is not initialized")
|
||||
)
|
||||
|
||||
func NewAPI(s *Service) *API {
|
||||
return &API{s}
|
||||
}
|
||||
|
||||
// API is class with methods available over RPC.
|
||||
type API struct {
|
||||
s *Service
|
||||
}
|
||||
|
||||
func (api *API) AddDappPermissions(ctx context.Context, perms DappPermissions) error {
|
||||
if api.s.db == nil {
|
||||
return ErrServiceNotInitialized
|
||||
}
|
||||
return api.s.db.AddPermissions(perms)
|
||||
}
|
||||
|
||||
func (api *API) GetDappPermissions(ctx context.Context) ([]DappPermissions, error) {
|
||||
if api.s.db == nil {
|
||||
return nil, ErrServiceNotInitialized
|
||||
}
|
||||
return api.s.db.GetPermissions()
|
||||
}
|
||||
|
||||
func (api *API) DeleteDappPermissions(ctx context.Context, name string) error {
|
||||
if api.s.db == nil {
|
||||
return ErrServiceNotInitialized
|
||||
}
|
||||
return api.s.db.DeletePermission(name)
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package permissions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func setupTestDB(t *testing.T) (*Database, func()) {
|
||||
tmpfile, err := ioutil.TempFile("", "perm-tests-")
|
||||
require.NoError(t, err)
|
||||
db, err := InitializeDB(tmpfile.Name(), "perm-tests")
|
||||
require.NoError(t, err)
|
||||
return db, func() {
|
||||
require.NoError(t, db.Close())
|
||||
require.NoError(t, os.Remove(tmpfile.Name()))
|
||||
}
|
||||
}
|
||||
|
||||
func setupTestAPI(t *testing.T) (*API, func()) {
|
||||
db, cancel := setupTestDB(t)
|
||||
return &API{s: &Service{db: db}}, cancel
|
||||
}
|
||||
|
||||
func TestDappPermissionsStored(t *testing.T) {
|
||||
api, cancel := setupTestAPI(t)
|
||||
defer cancel()
|
||||
|
||||
expected := []DappPermissions{
|
||||
{
|
||||
Name: "first",
|
||||
Permissions: []string{"r", "w"},
|
||||
},
|
||||
{
|
||||
Name: "second",
|
||||
Permissions: []string{"r", "x"},
|
||||
},
|
||||
{
|
||||
Name: "third",
|
||||
},
|
||||
}
|
||||
for _, perms := range expected {
|
||||
require.NoError(t, api.AddDappPermissions(context.TODO(), perms))
|
||||
}
|
||||
rst, err := api.GetDappPermissions(context.TODO())
|
||||
require.NoError(t, err)
|
||||
// sort in lexicographic order by name
|
||||
sort.Slice(rst, func(i, j int) bool {
|
||||
return rst[i].Name < rst[j].Name
|
||||
})
|
||||
require.Equal(t, expected, rst)
|
||||
|
||||
data, err := json.Marshal(rst)
|
||||
require.NoError(t, err)
|
||||
fmt.Println(string(data))
|
||||
}
|
||||
|
||||
func TestDappPermissionsReplacedOnUpdated(t *testing.T) {
|
||||
api, cancel := setupTestAPI(t)
|
||||
defer cancel()
|
||||
|
||||
perms := DappPermissions{
|
||||
Name: "first",
|
||||
Permissions: []string{"r", "w"},
|
||||
}
|
||||
require.NoError(t, api.AddDappPermissions(context.TODO(), perms))
|
||||
perms.Permissions = append(perms.Permissions, "x")
|
||||
require.NoError(t, api.AddDappPermissions(context.TODO(), perms))
|
||||
rst, err := api.GetDappPermissions(context.TODO())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, rst, 1)
|
||||
require.Equal(t, perms, rst[0])
|
||||
}
|
||||
|
||||
func TestDappPermissionsDeleted(t *testing.T) {
|
||||
api, cancel := setupTestAPI(t)
|
||||
defer cancel()
|
||||
|
||||
perms := DappPermissions{
|
||||
Name: "first",
|
||||
}
|
||||
require.NoError(t, api.AddDappPermissions(context.TODO(), perms))
|
||||
rst, err := api.GetDappPermissions(context.TODO())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, rst, 1)
|
||||
require.NoError(t, api.DeleteDappPermissions(context.TODO(), perms.Name))
|
||||
rst, err = api.GetDappPermissions(context.TODO())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, rst, 0)
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
package permissions
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/status-im/status-go/services/permissions/migrations"
|
||||
"github.com/status-im/status-go/sqlite"
|
||||
)
|
||||
|
||||
// Database sql wrapper for operations with browser objects.
|
||||
type Database struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// Close closes database.
|
||||
func (db Database) Close() error {
|
||||
return db.db.Close()
|
||||
}
|
||||
|
||||
// InitializeDB creates db file at a given path and applies migrations.
|
||||
func InitializeDB(path, password string) (*Database, error) {
|
||||
db, err := sqlite.OpenDB(path, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = migrations.Migrate(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Database{db: db}, nil
|
||||
}
|
||||
|
||||
type DappPermissions struct {
|
||||
Name string `json:"dapp"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
func (db *Database) AddPermissions(perms DappPermissions) (err error) {
|
||||
var (
|
||||
tx *sql.Tx
|
||||
insert *sql.Stmt
|
||||
)
|
||||
tx, err = db.db.Begin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
insert, err = tx.Prepare("INSERT OR REPLACE INTO dapps(name) VALUES(?)")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = insert.Exec(perms.Name)
|
||||
insert.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(perms.Permissions) == 0 {
|
||||
return
|
||||
}
|
||||
insert, err = tx.Prepare("INSERT INTO permissions(dapp_name, permission) VALUES(?, ?)")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer insert.Close()
|
||||
for _, perm := range perms.Permissions {
|
||||
_, err = insert.Exec(perms.Name, perm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetPermissions() (rst []DappPermissions, err error) {
|
||||
var (
|
||||
tx *sql.Tx
|
||||
rows *sql.Rows
|
||||
)
|
||||
tx, err = db.db.Begin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
// FULL and RIGHT joins are not supported
|
||||
rows, err = tx.Query("SELECT name FROM dapps")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
dapps := map[string]*DappPermissions{}
|
||||
for rows.Next() {
|
||||
perms := DappPermissions{}
|
||||
err = rows.Scan(&perms.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dapps[perms.Name] = &perms
|
||||
}
|
||||
rows, err = tx.Query("SELECT dapp_name, permission from permissions")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var (
|
||||
name string
|
||||
permission string
|
||||
)
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&name, &permission)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
dapps[name].Permissions = append(dapps[name].Permissions, permission)
|
||||
}
|
||||
rst = make([]DappPermissions, 0, len(dapps))
|
||||
for key := range dapps {
|
||||
rst = append(rst, *dapps[key])
|
||||
}
|
||||
return rst, nil
|
||||
}
|
||||
|
||||
func (db *Database) DeletePermission(name string) error {
|
||||
_, err := db.db.Exec("DELETE FROM dapps WHERE name = ?", name)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func bindata_read(data []byte, name string) ([]byte, error) {
|
||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, gz)
|
||||
gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
var __0001_permissions_down_sql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\x48\x49\x2c\x28\x28\xb6\xe6\x42\x12\x29\x48\x2d\xca\xcd\x2c\x2e\xce\xcc\xcf\x2b\xb6\xe6\x02\x04\x00\x00\xff\xff\xeb\x21\xe7\xd0\x2a\x00\x00\x00")
|
||||
|
||||
func _0001_permissions_down_sql() ([]byte, error) {
|
||||
return bindata_read(
|
||||
__0001_permissions_down_sql,
|
||||
"0001_permissions.down.sql",
|
||||
)
|
||||
}
|
||||
|
||||
var __0001_permissions_up_sql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\xce\x31\x0f\x82\x30\x10\x05\xe0\xbd\xbf\xe2\x8d\x90\xf8\x0f\x9c\x6a\x79\x68\x63\x6d\x4d\x39\x02\x4c\x86\x44\x06\x06\x90\xc8\xff\x4f\x4c\xa3\x91\xc4\xc1\xf5\xee\xdd\x77\xcf\x44\x6a\x21\x44\x1f\x1c\x61\x4b\xf8\x20\x60\x6b\x2b\xa9\x70\xef\x97\x65\x45\xa6\xe6\x7e\x1a\x20\x6c\x05\xd7\x68\x2f\x3a\x76\x38\xb3\x53\x39\x1a\x2b\xa7\x50\x0b\x62\x68\x6c\xb1\x57\xea\x0f\xb5\x0c\xcf\x69\x5c\xd7\xf1\x31\x27\x30\xc1\xb7\x4d\x4d\x39\x5f\x3b\xb7\x53\x5b\xec\x77\x53\x86\x48\x7b\xf4\xe9\x73\xf6\x3d\xcf\x11\x59\x32\xd2\x1b\x7e\xda\x66\xef\x71\xf0\x28\xe8\x28\x84\xd1\x95\xd1\x05\x55\xfe\x0a\x00\x00\xff\xff\x9e\x9a\xc6\xf0\xe8\x00\x00\x00")
|
||||
|
||||
func _0001_permissions_up_sql() ([]byte, error) {
|
||||
return bindata_read(
|
||||
__0001_permissions_up_sql,
|
||||
"0001_permissions.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
var _doc_go = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xc9\xb1\x0d\xc4\x20\x0c\x05\xd0\x9e\x29\xfe\x02\xd8\xfd\x6d\xe3\x4b\xac\x2f\x44\x82\x09\x78\x7f\xa5\x49\xfd\xa6\x1d\xdd\xe8\xd8\xcf\x55\x8a\x2a\xe3\x47\x1f\xbe\x2c\x1d\x8c\xfa\x6f\xe3\xb4\x34\xd4\xd9\x89\xbb\x71\x59\xb6\x18\x1b\x35\x20\xa2\x9f\x0a\x03\xa2\xe5\x0d\x00\x00\xff\xff\x60\xcd\x06\xbe\x4a\x00\x00\x00")
|
||||
|
||||
func doc_go() ([]byte, error) {
|
||||
return bindata_read(
|
||||
_doc_go,
|
||||
"doc.go",
|
||||
)
|
||||
}
|
||||
|
||||
// Asset loads and returns the asset for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func Asset(name string) ([]byte, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
return f()
|
||||
}
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
|
||||
// AssetNames returns the names of the assets.
|
||||
func AssetNames() []string {
|
||||
names := make([]string, 0, len(_bindata))
|
||||
for name := range _bindata {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() ([]byte, error){
|
||||
"0001_permissions.down.sql": _0001_permissions_down_sql,
|
||||
"0001_permissions.up.sql": _0001_permissions_up_sql,
|
||||
"doc.go": doc_go,
|
||||
}
|
||||
// AssetDir returns the file names below a certain
|
||||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
// AssetDir("") will return []string{"data"}.
|
||||
func AssetDir(name string) ([]string, error) {
|
||||
node := _bintree
|
||||
if len(name) != 0 {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
pathList := strings.Split(cannonicalName, "/")
|
||||
for _, p := range pathList {
|
||||
node = node.Children[p]
|
||||
if node == nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.Func != nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
rv := make([]string, 0, len(node.Children))
|
||||
for name := range node.Children {
|
||||
rv = append(rv, name)
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
type _bintree_t struct {
|
||||
Func func() ([]byte, error)
|
||||
Children map[string]*_bintree_t
|
||||
}
|
||||
var _bintree = &_bintree_t{nil, map[string]*_bintree_t{
|
||||
"0001_permissions.down.sql": &_bintree_t{_0001_permissions_down_sql, map[string]*_bintree_t{
|
||||
}},
|
||||
"0001_permissions.up.sql": &_bintree_t{_0001_permissions_up_sql, map[string]*_bintree_t{
|
||||
}},
|
||||
"doc.go": &_bintree_t{doc_go, map[string]*_bintree_t{
|
||||
}},
|
||||
}}
|
|
@ -0,0 +1,18 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
bindata "github.com/status-im/migrate/v4/source/go_bindata"
|
||||
"github.com/status-im/status-go/sqlite"
|
||||
)
|
||||
|
||||
// Migrate applies migrations.
|
||||
func Migrate(db *sql.DB) error {
|
||||
return sqlite.Migrate(db, bindata.Resource(
|
||||
AssetNames(),
|
||||
func(name string) ([]byte, error) {
|
||||
return Asset(name)
|
||||
},
|
||||
))
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
DROP TABLE dapps;
|
||||
DROP TABLE permissions;
|
|
@ -0,0 +1,9 @@
|
|||
CREATE TABLE IF NOT EXISTS dapps (
|
||||
name TEXT PRIMARY KEY
|
||||
) WITHOUT ROWID;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS permissions (
|
||||
dapp_name TEXT NOT NULL,
|
||||
permission TEXT NOT NULL,
|
||||
FOREIGN KEY(dapp_name) REFERENCES dapps(name) ON DELETE CASCADE
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
package sql
|
||||
|
||||
//go:generate go-bindata -pkg migrations -o ../bindata.go ./
|
|
@ -0,0 +1,62 @@
|
|||
package permissions
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
// NewService initializes service instance.
|
||||
func NewService() *Service {
|
||||
return &Service{}
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
mu sync.Mutex
|
||||
db *Database
|
||||
}
|
||||
|
||||
// Start a service.
|
||||
func (s *Service) Start(*p2p.Server) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartDatabase after dbpath and password will become known.
|
||||
func (s *Service) StartDatabase(dbpath, password string) (err error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.db, err = InitializeDB(dbpath, password)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) StopDatabase() error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if s.db != nil {
|
||||
return s.db.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop a service.
|
||||
func (s *Service) Stop() error {
|
||||
return s.StopDatabase()
|
||||
}
|
||||
|
||||
// APIs returns list of available RPC APIs.
|
||||
func (s *Service) APIs() []rpc.API {
|
||||
return []rpc.API{
|
||||
{
|
||||
Namespace: "permissions",
|
||||
Version: "0.1.0",
|
||||
Service: NewAPI(s),
|
||||
Public: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Protocols returns list of p2p protocols.
|
||||
func (s *Service) Protocols() []p2p.Protocol {
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue