Comparing version 1.0.6 to 1.0.7
45
index.js
@@ -77,3 +77,2 @@ const { basename, dirname } = require('path') | ||
} | ||
const encryptPaths = encryption.encryptPaths || true; | ||
const enc = { | ||
@@ -83,3 +82,2 @@ key: encKey, | ||
algo: encryption.algo || DEFAULT_CRYPT_ALGO, | ||
encryptPaths, | ||
dirLevels: encryption.dirLevels || 4, | ||
@@ -97,9 +95,6 @@ encPathPadding: () => ENC_PAD_SEP + randomstring.generate(1 + Math.floor(2*Math.random())) | ||
} | ||
const direntDir = dir => encryptPaths ? encryptPath(dir + DIR_ENT_DIR_SUFFIX) : null | ||
const direntDir = dir => encryptPath(dir + DIR_ENT_DIR_SUFFIX) | ||
const direntFile = (dirent, path) => dirent + '/' + shasum(DIR_ENT_FILE_PREFIX + ' ' + path) | ||
const _metadata = (client) => async (path) => { | ||
if (!encryptPaths) { | ||
return client.metadata(path) | ||
} | ||
let meta | ||
@@ -154,5 +149,2 @@ try { | ||
list: async (path) => { | ||
if (!encryptPaths) { | ||
return await client.list(path) | ||
} | ||
const dirent = direntDir(path) | ||
@@ -167,3 +159,3 @@ const entries = await client.list(dirent) | ||
read: async (path, callback) => { | ||
const realPath = encryptPaths ? encryptPath(path) : path | ||
const realPath = encryptPath(path) | ||
const cipher = crypt.startDecryptStream(enc) | ||
@@ -179,18 +171,16 @@ return client.read(realPath, | ||
// if encrypting paths, write dirent file(s) for all parent directories | ||
if (encryptPaths) { | ||
let p = path | ||
while (true) { | ||
const direntGenerator = function* () { | ||
yield encrypt(p + enc.encPathPadding(), enc) | ||
} | ||
const dir = direntDir(dirname(p)) | ||
const df = direntFile(dir, p); | ||
if (!(await client.write(df, direntGenerator()))) { | ||
throw new MobilettoError('write: error writing dirent file') | ||
} | ||
p = dirname(p) | ||
if (p === '.' || p === '') { | ||
break | ||
} | ||
let p = path | ||
while (true) { | ||
const direntGenerator = function* () { | ||
yield encrypt(p + enc.encPathPadding(), enc) | ||
} | ||
const dir = direntDir(dirname(p)) | ||
const df = direntFile(dir, p); | ||
if (!(await client.write(df, direntGenerator()))) { | ||
throw new MobilettoError('write: error writing dirent file') | ||
} | ||
p = dirname(p) | ||
if (p === '.' || p === '') { | ||
break | ||
} | ||
} | ||
@@ -212,7 +202,2 @@ | ||
const recursive = (options && options.recursive) || false | ||
const quiet = (options && options.quiet) || false | ||
if (!encryptPaths) { | ||
return client.remove(path, {recursive, quiet}) | ||
} | ||
if (recursive) { | ||
@@ -219,0 +204,0 @@ // ugh. we have to iterate over all dirent files, and remove each file/subdir one by one |
{ | ||
"name": "mobiletto", | ||
"version": "1.0.6", | ||
"version": "1.0.7", | ||
"description": "A storage abstraction layer", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -10,4 +10,9 @@ Mobiletto | ||
Today the supported drivers are: | ||
* `s3`: read/write an Amazon S3 bucket | ||
* `local`: read/write to local filesystem | ||
# Basic usage | ||
const { mobiletto, readFile } = require('mobiletto') | ||
const { mobiletto } = require('mobiletto') | ||
@@ -79,2 +84,9 @@ // General usage | ||
# Alternate usage | ||
Import the fully-scoped module and use the `connect` function: | ||
const storage = require('mobiletto') | ||
const s3 = await storage.connect('s3', aws_key, aws_secret, {bucket: 'bk', region: 'us-east-1'}) | ||
const objectData = await s3.readFile('some/path') | ||
# Transparent Encryption | ||
@@ -87,4 +99,3 @@ Enable transparent client-side encryption: | ||
iv: randomstring.generate(128), // optional, default is to derive IV from key | ||
algo: 'aes-256-cbc', // optional, aes-256-cbc is the default | ||
encryptPaths: true // optional, default is true | ||
algo: 'aes-256-cbc' // optional, aes-256-cbc is the default | ||
} | ||
@@ -95,26 +106,20 @@ const api = await mobiletto(driverName, key, secret, opts, encryption) | ||
// Subsequent read operations will decrypt data (client side) when reading | ||
// If `encryptPaths` is true, then path names will be hashed using the encrpytion key | ||
Note that when `encryptPaths` is enabled, `list` commands are considerably more inefficient, | ||
especially for directories with a large number of files. | ||
What's happening? A separate "directory entry" directory (encrypted) tracks what files are in that | ||
What's happening? A separate "directory entry" (dirent) directory (encrypted) tracks what files are in that | ||
directory (aka the dirent directory). | ||
* The `list` command reads the directory entry files, decrypts each path listed; then returns metadata for each file | ||
* `list` commands are more inefficient, especially for directories with a large number of files | ||
* The `write` command writes dirent files in each parent's dirent directory, recursively; then writes the file | ||
* `write` commands will incur O(N) writes, with N = depth in the directory hierarchy | ||
* The `remove` command removes the corresponding dirent file, and its parent if empty, recursively; then removes the file | ||
* Note: Recursive removal on large and deep filesystems can be an expensive operation | ||
* Non-recursive `remove` commands will incur O(N) reads and potentially as many deletes, with N = depth in the directory hierarchy | ||
* Recursive `remove` commands on large and deep filesystems can be expensive | ||
Note that even with `encryptPaths` enabled, an adversary with full visibility into your encrypted storage, | ||
even without the key, can still see the total number of directories and how many files are in each, and with some | ||
effort, discover some or all of the overall hierarchical structure. They would not know the names of the | ||
directories/files unless they also knew your encryption key or had otherwise successfully cracked the encryption. | ||
All bets are off then! | ||
Note that even with client-side encryption enabled, an adversary with full visibility into your encrypted server-side | ||
storage, even without the key, can still see the total number of directories and how many files are in each, and with | ||
some effort, discover some or all of the overall structure of the directory hierarchy. | ||
*Note: Use a relatively flat structure for better security.* | ||
The adversary would not know the names of the directories/files unless they also knew your encryption | ||
key or had otherwise successfully cracked the encryption. All bets are off then! | ||
# Alternate usage: import fully scoped module and use `connect` | ||
const storage = require('mobiletto') | ||
const s3 = await storage.connect('s3', aws_key, aws_secret, {bucket: 'bk', region: 'us-east-1'}) | ||
const objectData = await s3.readFile('some/path') | ||
# Driver Interface | ||
@@ -121,0 +126,0 @@ A driver is any JS file that exports a 'storageClient' function with this signature: |
156
64228
1078