Comparing version 0.3.0 to 0.4.0
{ | ||
"name": "dar-server", | ||
"version": "0.3.0", | ||
"version": "0.4.0", | ||
"description": "Filesystem backend for document archive", | ||
@@ -16,4 +16,5 @@ "main": "index.js", | ||
"parse-formdata": "^1.0.2", | ||
"yargs": "^11.0.0" | ||
"yargs": "^11.0.0", | ||
"fs-extra": "^5.0.0" | ||
} | ||
} |
const readArchive = require('./readArchive') | ||
const writeArchive = require('./writeArchive') | ||
const cloneArchive = require('./cloneArchive') | ||
const path = require('path') | ||
@@ -14,14 +15,18 @@ | ||
read(archiveDir) { | ||
return new Promise( async (resolve) => { | ||
let records = await readArchive(archiveDir, { noBinaryContent: true, ignoreDotFiles: true }) | ||
// Turn binaries into urls | ||
Object.keys(records).forEach(recordPath => { | ||
let record = records[recordPath] | ||
if (record._binary) { | ||
delete record._binary | ||
record.encoding = 'url' | ||
record.data = path.join(archiveDir, record.path) | ||
} | ||
}) | ||
resolve(records) | ||
return new Promise( async (resolve, reject) => { | ||
try { | ||
let rawArchive = await readArchive(archiveDir, { noBinaryContent: true, ignoreDotFiles: true }) | ||
// Turn binaries into urls | ||
Object.keys(rawArchive.resources).forEach(recordPath => { | ||
let record = rawArchive.resources[recordPath] | ||
if (record._binary) { | ||
delete record._binary | ||
record.encoding = 'url' | ||
record.data = path.join(archiveDir, record.path) | ||
} | ||
}) | ||
resolve(rawArchive) | ||
} catch(err) { | ||
reject(err) | ||
} | ||
}) | ||
@@ -31,8 +36,23 @@ } | ||
write(archiveDir, rawArchive) { | ||
return new Promise( async (resolve) => { | ||
await _convertBlobs(rawArchive) | ||
await writeArchive(archiveDir, rawArchive) | ||
resolve(JSON.stringify({ version: 0 })) | ||
return new Promise( async (resolve, reject) => { | ||
try { | ||
await _convertBlobs(rawArchive) | ||
let version = await writeArchive(archiveDir, rawArchive) | ||
resolve(JSON.stringify({ version })) | ||
} catch(err) { | ||
reject(err) | ||
} | ||
}) | ||
} | ||
clone(archiveDir, newArchiveDir) { | ||
return new Promise( async (resolve, reject) => { | ||
try { | ||
await cloneArchive(archiveDir, newArchiveDir) | ||
resolve() | ||
} catch(err) { | ||
reject(err) | ||
} | ||
}) | ||
} | ||
} | ||
@@ -43,6 +63,7 @@ | ||
*/ | ||
async function _convertBlobs(records) { | ||
let paths = Object.keys(records) | ||
async function _convertBlobs(rawArchive) { | ||
let resources = rawArchive.resources | ||
let paths = Object.keys(resources) | ||
for (var i = 0; i < paths.length; i++) { | ||
let record = records[paths[i]] | ||
let record = resources[paths[i]] | ||
if (record.encoding === 'blob') { | ||
@@ -49,0 +70,0 @@ record.data = await _blobToArrayBuffer(record.data) |
const fs = require('fs') | ||
const path = require('path') | ||
const listDir = require('./listDir') | ||
const httpError = require('./httpError') | ||
const { isDocumentArchive } = require('./util') | ||
@@ -15,21 +14,22 @@ // these extensions are considered to have text content | ||
- `ignoreDotFiles`: ignore dot-files | ||
- versioning: set to true if versioning should be enabled | ||
*/ | ||
module.exports = async function readArchive(archiveDir, opts = {}) { | ||
// make sure that the given path is a dar | ||
if (await _isDocumentArchive(archiveDir)) { | ||
if (await isDocumentArchive(archiveDir)) { | ||
// first get a list of stats | ||
const entries = await listDir(archiveDir, opts) | ||
// then get file records as specified TODO:link | ||
let result = {} | ||
let resources = {} | ||
for (var i = 0; i < entries.length; i++) { | ||
let entry = entries[i] | ||
let record = await _getFileRecord(entry, opts) | ||
result[record.path] = record | ||
resources[record.path] = record | ||
} | ||
// HACK: we should not mix records with the version property! | ||
// TODO: Change the result to { records: {...}, version: "0" } | ||
result.version = "0" | ||
return result | ||
return { | ||
resources, | ||
version: "0" | ||
} | ||
} else { | ||
throw httpError(500, archiveDir + ' is not a valid document archive') | ||
throw new Error(archiveDir + ' is not a valid document archive.') | ||
} | ||
@@ -40,3 +40,3 @@ } | ||
/* | ||
Provides a record for a file as it is used for the DocumentArchive presistence protocol. | ||
Provides a record for a file as it is used for the DocumentArchive persistence protocol. | ||
@@ -95,14 +95,3 @@ Binary files can be exluced using `opts.noBinaryData`. | ||
async function _isDocumentArchive(archiveDir) { | ||
// assuming it is a DAR if the folder exists and there is a manifest.xml | ||
return _fileExists(path.join(archiveDir, 'manifest.xml')) | ||
} | ||
function _fileExists(path) { | ||
return new Promise(resolve => { | ||
fs.exists(path, (exists) => { | ||
resolve(exists) | ||
}) | ||
}) | ||
} | ||
@@ -109,0 +98,0 @@ function _isTextFile(f) { |
@@ -5,4 +5,4 @@ const fs = require('fs') | ||
const readArchive = require('./readArchive') | ||
const readVersion = require('./readVersion') | ||
const writeArchive = require('./writeArchive') | ||
const cloneArchive = require('./cloneArchive') | ||
@@ -34,8 +34,12 @@ const DOT = '.'.charCodeAt(0) | ||
if (relDir.charCodeAt(0) === DOT) { | ||
return res.status(403) | ||
return res.status(403).send() | ||
} | ||
try { | ||
let records = await readArchive(archiveDir, { noBinaryContent: true, ignoreDotFiles: true }) | ||
Object.keys(records).forEach(recordPath => { | ||
let record = records[recordPath] | ||
let rawArchive = await readArchive(archiveDir, { | ||
noBinaryContent: true, | ||
ignoreDotFiles: true, | ||
versioning: opts.versioning | ||
}) | ||
Object.keys(rawArchive.resources).forEach(recordPath => { | ||
let record = rawArchive.resources[recordPath] | ||
if (record._binary) { | ||
@@ -47,8 +51,6 @@ delete record._binary | ||
}) | ||
// TODO: we should not mix records and the version property | ||
records.version = '0' | ||
res.json(records) | ||
res.json(rawArchive) | ||
} catch(err) { // eslint-disable-line no-catch-shadow | ||
console.error(err) | ||
res.status(err.httpStatus) | ||
res.status(404).send() | ||
} | ||
@@ -59,4 +61,2 @@ }) | ||
Endpoint for uploading files. | ||
NOTE: Versioning is disabled atm. We may wand to back it via Git. | ||
*/ | ||
@@ -68,18 +68,12 @@ app.put(apiUrl+'/:dar', (req, res) => { | ||
console.error(err) | ||
return res.status(500) | ||
return res.status(500).send() | ||
} | ||
let archiveDir = path.join(rootDir, id) | ||
fs.stat(archiveDir, async (err) => { | ||
if (err) return res.status(404) | ||
if (err) return res.status(404).send() | ||
try { | ||
let archive = JSON.parse(formData.fields._archive) | ||
let version = await readVersion(archiveDir) | ||
// For now the client must provide the correct version number | ||
if (version !== archive.version) { | ||
res.status(500).send('Incompatible version') | ||
return | ||
} | ||
formData.parts.forEach((part) => { | ||
let filename = part.filename | ||
let record = archive[filename] | ||
let record = archive.resources[filename] | ||
if (!record) { | ||
@@ -92,22 +86,30 @@ console.error('No document record registered for blob', filename) | ||
}) | ||
// TODO: need a generic way to create a version | ||
// with git we would use the commit sha of the latest commit | ||
// TODO: without git this is kind of dangerous as we can't rollback | ||
await writeArchive(archiveDir, archive) | ||
// TODO: we could do something like this | ||
// let newVersion = String(Number.parseInt(version, 10) + 1) | ||
// await writeVersion(archiveDir, newVersion) | ||
// ... but instead we just return the same version all the time | ||
let newVersion = version | ||
res.status(200).json({ version: newVersion }) | ||
let version = await writeArchive(archiveDir, archive, { | ||
versioning: opts.versioning | ||
}) | ||
res.status(200).json({ version }) | ||
} catch (err) { // eslint-disable-line no-catch-shadow | ||
console.error(err) | ||
res.status(500) | ||
res.status(500).send() | ||
} | ||
}) | ||
// TODO: if done send `{ version: newVersion }` | ||
res.status(500) | ||
res.status(500).send() | ||
}) | ||
}) | ||
/* | ||
Used to clone/fork an archive under a new id | ||
*/ | ||
app.put(apiUrl+'/:dar/clone/:newdar', async (req, res) => { | ||
let originalPath = path.join(rootDir, req.params.dar) | ||
let newPath = path.join(rootDir, req.params.newdar) | ||
try { | ||
await cloneArchive(originalPath, newPath) | ||
res.status(200).json({ status: 'ok' }) | ||
} catch(err) { // eslint-disable-line no-catch-shadow | ||
console.error(err) | ||
res.status(500).send() | ||
} | ||
}) | ||
// this endpoint is used for serving files statically | ||
@@ -117,3 +119,3 @@ app.get(apiUrl+'/:dar/assets/:file', (req, res) => { | ||
fs.stat(filePath, (err) => { | ||
if (err) return res.status(404) | ||
if (err) return res.status(404).send() | ||
res.sendFile(filePath) | ||
@@ -120,0 +122,0 @@ }) |
const fs = require('fs') | ||
const path = require('path') | ||
module.exports = async function writeArchive(archiveDir, rawArchive) { | ||
let files = Object.keys(rawArchive) | ||
return Promise.all(files.map(f => { | ||
let record = rawArchive[f] | ||
/* | ||
TODO: Implement versioning backed by Git | ||
- Check if rawArchive.version === latest Git sha | ||
- After saving `git add` all changed files and `git commit` them | ||
- Return new sha (newVersion) to client | ||
*/ | ||
module.exports = async function writeArchive(archiveDir, rawArchive, opts = {}) { | ||
let resourceNames = Object.keys(rawArchive.resources) | ||
let newVersion = "0" | ||
if (opts.versioning) { | ||
console.warn('Git based versioning is not yet implemented.') | ||
} | ||
return Promise.all(resourceNames.map(f => { | ||
let record = rawArchive.resources[f] | ||
switch(record.encoding) { | ||
@@ -19,3 +31,5 @@ case 'utf8': { | ||
} | ||
})) | ||
})).then(() => { | ||
return newVersion | ||
}) | ||
} | ||
@@ -22,0 +36,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
571
1
15
0
17503
5
12
+ Addedfs-extra@^5.0.0
+ Addedfs-extra@5.0.0(transitive)
+ Addedgraceful-fs@4.2.11(transitive)
+ Addedjsonfile@4.0.0(transitive)
+ Addeduniversalify@0.1.2(transitive)