Skip to content
This repository has been archived by the owner on Jan 7, 2022. It is now read-only.

Allow for specification of dat secret storage directory. #193

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module.exports = createDat
* @param {Boolean} [opts.createIfMissing = true] - Create storage if it does not exit.
* @param {Boolean} [opts.errorIfExists = false] - Error if storage exists.
* @param {Boolean} [opts.temp = false] - Use random-access-memory for temporary storage
* @param {string} [opts.secretDir] - Directory for storage of secrets
* @param {function(err, dat)} cb - callback that returns `Dat` instance
* @see defaultStorage for storage information
*/
Expand Down
41 changes: 26 additions & 15 deletions lib/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ module.exports = defaultStorage
* Object is a hyperdrive storage object `{metadata: fn, content: fn}`.
* @param {object} [opts] - options
* @param {Boolean} [opts.temp] - Use temporary storage (random-access-memory)
* @param {string} [opts.secretDir] - Directory for storage of secrets.
* @returns {object} hyperdrive storage object
*/
function defaultStorage (storage, opts) {
// Use custom storage or ram
if (typeof storage !== 'string') return storage
if (opts.temp) return ram
if (opts.latest === false) {
// Store as SLEEP files inluding content.data
// Store as SLEEP files including content.data
return {
metadata: function (name, opts) {
// I don't think we want this, we may get multiple 'ogd' sources
Expand All @@ -37,24 +38,34 @@ function defaultStorage (storage, opts) {
}

try {
// Store in .dat with secret in ~/.dat
if (fs.statSync(storage).isDirectory()) {
return datStore(storage)
makeDirectoryIfNotExist(storage)

if (typeof opts.secretDir !== 'undefined') {
try {
makeDirectoryIfNotExist(opts.secretDir)
} catch (e) {
throw new Error('Secret dir must be dir')
}
}
return datStore(storage, opts)
} catch (e) {
// Does not exist, make dir
throw new Error('Storage must be dir or opts.temp')
}

function makeDirectoryIfNotExist (path) {
try {
fs.mkdirSync(storage)
if (fs.statSync(path).isDirectory()) {
return true
}
} catch (e) {
// Invalid path
throw new Error('Invalid storage path')
// Path does not exist, make dir.
try {
fs.mkdirSync(storage)
return true
} catch (e) {
throw new Error('Invalid path ' + path)
}
}
return datStore(storage)
}
error()

function error () {
// TODO: single file sleep storage
throw new Error('Storage must be dir or opts.temp')
return false
}
}
11 changes: 9 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,24 +102,31 @@ We'll go through what these are for and a few of the common usages of each eleme

### Storage

Every dat archive has **storage**, this is the required first argument for dat-node. By default, we use [dat-storage](http://github.com/datproject/dat-storage) which stores the secret key in `~/.dat/` and the rest of the ddata in `dir/.dat`. Other common options are:
Every dat archive has **storage**, this is the required first argument for dat-node. By default, we use [dat-storage](http://github.com/datproject/dat-storage) which stores the secret key in `~/.dat/` and the rest of the data in `dir/.dat`. Other common options are:

* **Persistent storage**: Stored files in `/my-dir` and metadata in `my-dir/.dat` by passing `/my-dir` as the first argument.
* **Temporary Storage**: Use the `temp: true` option to keep metadata stored in memory.
* **Secret Key Dir**: Specify secretDir in the second opts argument in the form of {secretDir: '/my-secrets'} to store files
in /my-dir and secrets in /my-secrets respectively.

```js
// Permanent Storage
Dat('/my-dir', function (err, dat) {
// Do Dat Stuff
})

// Secret Storage
Dat('/my-dir', {secretDir: '/my-secrets'}, function (err, dat) {
// Do Dat Stuff
})

// Temporary Storage
Dat('/my-dir', {temp: true}, function (err, dat) {
// Do Dat Stuff
})
```

Both of these will import files from `/my-dir` when doing `dat.importFiles()` but only the first will make a `.dat` folder and keep the metadata on disk.
All of these will import files from `/my-dir` when doing `dat.importFiles()` but only the first two will make a `.dat` folder and keep the metadata on disk.

The storage argument can also be passed through to hyperdrive for more advanced storage use cases.

Expand Down
57 changes: 57 additions & 0 deletions test/download.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,63 @@ test('download: Download with default opts', function (t) {
})
})

test('download: Download with secretDir opt', function (t) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! Sorry was not looking closely at this before, we only have a secret directory when you create the Dat (e.g. sharing).

These tests look good otherwise. Can you also just make sure the downSecretDir has a key in it?

shareFixtures(function (err, shareKey, closeShare) {
t.error(err, 'error')

tmpDir(function (err, downDir, cleanup) {
t.error(err, 'error')

tmpDir(function (err, downSecretDir, cleanupSecret) {
t.error(err, 'error')

Dat(downDir, {secretDir: downSecretDir, key: shareKey}, function (err, dat) {
t.error(err, 'error')
t.ok(dat, 'callsback with dat object')
t.ok(dat.key, 'has key')
t.ok(dat.archive, 'has archive')
t.notOk(dat.writable, 'archive not writable')

var stats = dat.trackStats()
var network = dat.joinNetwork(function () {
t.pass('joinNetwork calls back okay')
})
network.once('connection', function () {
t.pass('connects via network')
})
var archive = dat.archive
archive.once('content', function () {
t.pass('gets content')
archive.content.on('sync', done)
})

function done () {
var st = stats.get()
t.ok(st.version === archive.version, 'stats version correct')
t.ok(st.downloaded === st.length, 'all blocks downloaded')
helpers.verifyFixtures(t, archive, function (err) {
t.error(err, 'error')
dat.close(function (err) {
t.error(err, 'error')
cleanup(function (err) {
t.error(err, 'error')
cleanupSecret(function (err) {
t.error(err, 'error')
closeShare(function (err) {
t.error(err, 'error')
t.end()
})
})
})
})
})
}
})
})
})
})
})

// TODO:
// rest of download tests
// tests will be a lot better with some download-finished type check
Expand Down