Skip to content

Commit

Permalink
fix: iOS background crash
Browse files Browse the repository at this point in the history
Signed-off-by: D4ryl00 <d4ryl00@gmail.com>
  • Loading branch information
D4ryl00 committed Mar 8, 2022
1 parent 033e8ee commit 699671b
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 38 deletions.
3 changes: 2 additions & 1 deletion ds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ func TestCase(t *testing.T) {
defer cancel()

key := testingKey(t)
ds, err := NewSQLCipherDatastore("sqlite3", filepath.Join(t.TempDir(), "test.sqlite"), "blocks", key)
salt := testingSalt(t)
ds, err := NewSQLCipherDatastore("sqlite3", filepath.Join(t.TempDir(), "test.sqlite"), "blocks", key, salt)
require.NoError(t, err)
require.NoError(t, ds.Put(ctx, datastore.KeyWithNamespaces([]string{"A", "B"}), ([]byte)("42")))
qr, err := ds.Query(ctx, query.Query{Prefix: "a"})
Expand Down
47 changes: 31 additions & 16 deletions fsrepo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ func TestInitIdempotence(t *testing.T) {
t.Parallel()
path := testRepoPath("", t)
key := testingKey(t)
salt := testingSalt(t)
for i := 0; i < 10; i++ {
require.NoError(t, Init(path, key, &config.Config{Datastore: testingDatastoreConfig()}), i)
require.NoError(t, Init(path, key, salt, &config.Config{Datastore: testingDatastoreConfig()}), i)
}
}

Expand All @@ -53,6 +54,14 @@ func testingKey(t *testing.T) []byte {
return buf
}

func testingSalt(t *testing.T) []byte {
t.Helper()
buf := make([]byte, 32)
_, err := rand.Read(buf)
require.NoError(t, err)
return buf
}

func TestCanManageReposIndependently(t *testing.T) {
t.Parallel()
pathA := testRepoPath("a", t)
Expand All @@ -61,22 +70,25 @@ func TestCanManageReposIndependently(t *testing.T) {
aKey := testingKey(t)
bKey := testingKey(t)

aSalt := testingSalt(t)
bSalt := testingSalt(t)

t.Log("initialize two repos")
assert.Nil(Init(pathA, aKey, &config.Config{Datastore: testingDatastoreConfig()}), t, "a", "should initialize successfully")
assert.Nil(Init(pathB, bKey, &config.Config{Datastore: testingDatastoreConfig()}), t, "b", "should initialize successfully")
assert.Nil(Init(pathA, aKey, aSalt, &config.Config{Datastore: testingDatastoreConfig()}), t, "a", "should initialize successfully")
assert.Nil(Init(pathB, bKey, bSalt, &config.Config{Datastore: testingDatastoreConfig()}), t, "b", "should initialize successfully")

t.Log("ensure repos initialized")
isInit, err := IsInitialized(pathA, aKey)
isInit, err := IsInitialized(pathA, aKey, aSalt)
require.NoError(t, err)
require.True(t, isInit, "a should be initialized")
isInit, err = IsInitialized(pathB, bKey)
isInit, err = IsInitialized(pathB, bKey, bSalt)
require.NoError(t, err)
require.True(t, isInit, "b should be initialized")

t.Log("open the two repos")
repoA, err := Open(pathA, aKey)
repoA, err := Open(pathA, aKey, aSalt)
assert.Nil(err, t, "a")
repoB, err := Open(pathB, bKey)
repoB, err := Open(pathB, bKey, bSalt)
assert.Nil(err, t, "b")

t.Log("close and remove b while a is open")
Expand All @@ -96,11 +108,12 @@ func TestDatastoreGetNotAllowedAfterClose(t *testing.T) {
path := testRepoPath("test", t)

key := testingKey(t)
isInit, err := IsInitialized(path, key)
salt := testingSalt(t)
isInit, err := IsInitialized(path, key, salt)
require.NoError(t, err)
require.False(t, isInit)
require.NoError(t, Init(path, key, &config.Config{Datastore: testingDatastoreConfig()}))
r, err := Open(path, key)
require.NoError(t, Init(path, key, salt, &config.Config{Datastore: testingDatastoreConfig()}))
r, err := Open(path, key, salt)
require.NoError(t, err)

k := "key"
Expand All @@ -119,17 +132,18 @@ func TestDatastorePersistsFromRepoToRepo(t *testing.T) {

path := testRepoPath("test", t)
key := testingKey(t)
salt := testingSalt(t)

assert.Nil(Init(path, key, &config.Config{Datastore: testingDatastoreConfig()}), t)
r1, err := Open(path, key)
assert.Nil(Init(path, key, salt, &config.Config{Datastore: testingDatastoreConfig()}), t)
r1, err := Open(path, key, salt)
assert.Nil(err, t)

k := "key"
expected := []byte(k)
assert.Nil(r1.Datastore().Put(ctx, datastore.NewKey(k), expected), t, "using first repo, Put should be successful")
assert.Nil(r1.Close(), t)

r2, err := Open(path, key)
r2, err := Open(path, key, salt)
assert.Nil(err, t)
actual, err := r2.Datastore().Get(ctx, datastore.NewKey(k))
assert.Nil(err, t, "using second repo, Get should be successful")
Expand All @@ -142,12 +156,13 @@ func TestOpenMoreThanOnceInSameProcess(t *testing.T) {
path := testRepoPath("", t)

key := testingKey(t)
salt := testingSalt(t)

assert.Nil(Init(path, key, &config.Config{Datastore: testingDatastoreConfig()}), t)
assert.Nil(Init(path, key, salt, &config.Config{Datastore: testingDatastoreConfig()}), t)

r1, err := Open(path, key)
r1, err := Open(path, key, salt)
assert.Nil(err, t, "first repo should open successfully")
r2, err := Open(path, key)
r2, err := Open(path, key, salt)
assert.Nil(err, t, "second repo should open successfully")
assert.True(r1 == r2, t, "second open returns same value")

Expand Down
14 changes: 7 additions & 7 deletions init.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

const tableName = "ipfs"

func IsInitialized(dbPath string, key []byte) (bool, error) {
func IsInitialized(dbPath string, key []byte, salt []byte) (bool, error) {
// packageLock is held to ensure that another caller doesn't attempt to
// Init or Remove the repo while this call is in progress.
packageLock.Lock()
Expand All @@ -19,13 +19,13 @@ func IsInitialized(dbPath string, key []byte) (bool, error) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

return isInitialized(ctx, dbPath, key)
return isInitialized(ctx, dbPath, key, salt)
}

// isInitialized reports whether the repo is initialized. Caller must
// hold the packageLock.
func isInitialized(ctx context.Context, dbPath string, key []byte) (bool, error) {
uds, err := OpenSQLCipherDatastore("sqlite3", dbPath, tableName, key)
func isInitialized(ctx context.Context, dbPath string, key []byte, salt []byte) (bool, error) {
uds, err := OpenSQLCipherDatastore("sqlite3", dbPath, tableName, key, salt)
if err == ErrDatabaseNotFound {
return false, nil
}
Expand All @@ -44,7 +44,7 @@ func isInitialized(ctx context.Context, dbPath string, key []byte) (bool, error)
return initialized, nil
}

func Init(dbPath string, key []byte, conf *config.Config) error {
func Init(dbPath string, key []byte, salt []byte, conf *config.Config) error {
// packageLock must be held to ensure that the repo is not initialized more
// than once.
packageLock.Lock()
Expand All @@ -53,15 +53,15 @@ func Init(dbPath string, key []byte, conf *config.Config) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

isInit, err := isInitialized(ctx, dbPath, key)
isInit, err := isInitialized(ctx, dbPath, key, salt)
if err != nil {
return err
}
if isInit {
return nil
}

uds, err := NewSQLCipherDatastore("sqlite3", dbPath, tableName, key)
uds, err := NewSQLCipherDatastore("sqlite3", dbPath, tableName, key, salt)
if err != nil {
return err
}
Expand Down
8 changes: 4 additions & 4 deletions open.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ var (
onlyOne repo.OnlyOne
)

func Open(dbPath string, key []byte) (repo.Repo, error) {
func Open(dbPath string, key []byte, salt []byte) (repo.Repo, error) {
fn := func() (repo.Repo, error) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
return open(ctx, dbPath, key)
return open(ctx, dbPath, key, salt)
}
return onlyOne.Open(dbPath, fn)
}

func open(ctx context.Context, dbPath string, key []byte) (repo.Repo, error) {
func open(ctx context.Context, dbPath string, key []byte, salt []byte) (repo.Repo, error) {
packageLock.Lock()
defer packageLock.Unlock()

uroot, err := OpenSQLCipherDatastore("sqlite3", dbPath, tableName, key)
uroot, err := OpenSQLCipherDatastore("sqlite3", dbPath, tableName, key, salt)
if err != nil {
return nil, errors.Wrap(err, "instantiate datastore")
}
Expand Down
16 changes: 9 additions & 7 deletions repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,24 @@ import (

func TestRepo(t *testing.T) {
key := testingKey(t)
salt := testingSalt(t)
dbPath := filepath.Join(t.TempDir(), "db.sqlite")

isInit, err := IsInitialized(dbPath, key)
isInit, err := IsInitialized(dbPath, key, salt)
require.NoError(t, err)
require.False(t, isInit)

err = Init(dbPath, key, &config.Config{})
err = Init(dbPath, key, salt, &config.Config{})
require.NoError(t, err)

isInit, err = IsInitialized(dbPath, key)
isInit, err = IsInitialized(dbPath, key, salt)
require.NoError(t, err)
require.True(t, isInit)

err = Init(dbPath, key, &config.Config{})
err = Init(dbPath, key, salt, &config.Config{})
require.NoError(t, err)

r, err := Open(dbPath, key)
r, err := Open(dbPath, key, salt)
require.NoError(t, err)
defer requireClose(t, r)

Expand All @@ -42,12 +43,13 @@ func TestRepo(t *testing.T) {

func TestSetAPIAddrTwice(t *testing.T) {
key := testingKey(t)
salt := testingSalt(t)
dbPath := filepath.Join(t.TempDir(), "db.sqlite")

err := Init(dbPath, key, &config.Config{})
err := Init(dbPath, key, salt, &config.Config{})
require.NoError(t, err)

r, err := Open(dbPath, key)
r, err := Open(dbPath, key, salt)
require.NoError(t, err)
defer requireClose(t, r)

Expand Down
12 changes: 9 additions & 3 deletions sqlcipher.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package encrepo

import (
"encoding/base64"
"fmt"
"os"

Expand All @@ -14,18 +15,23 @@ func NewSQLiteDatastore(driver, dbPath, table string) (*sqlds.Datastore, error)
return (&sqliteds.Options{Driver: driver, DSN: dbPath, Table: table}).Create()
}

func NewSQLCipherDatastore(driver, dbPath, table string, key []byte) (*sqlds.Datastore, error) {
func NewSQLCipherDatastore(driver, dbPath, table string, key []byte, salt []byte) (*sqlds.Datastore, error) {
if err := checkDBCrypto(dbPath, len(key) != 0); err != nil {
return nil, err
}

saltString := base64.URLEncoding.EncodeToString(salt)
dbPath = fmt.Sprintf("%s?journal_mode=WAL&cipher_plaintext_header_size=32&cipher_salt=%s", dbPath, saltString)

return (&sqliteds.Options{Driver: driver, DSN: dbPath, Table: table, Key: key}).Create()
}

func OpenSQLCipherDatastore(driver, dbPath, table string, key []byte) (*sqlds.Datastore, error) {
func OpenSQLCipherDatastore(driver, dbPath, table string, key []byte, salt []byte) (*sqlds.Datastore, error) {
if _, err := os.Stat(dbPath); os.IsNotExist(err) {
return nil, ErrDatabaseNotFound
}
return NewSQLCipherDatastore(driver, dbPath, table, key)

return NewSQLCipherDatastore(driver, dbPath, table, key, salt)
}

var (
Expand Down

0 comments on commit 699671b

Please sign in to comment.