Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ellx

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ellx - npm Package Compare versions

Comparing version 0.0.5 to 0.1.0

25

index.js
#!/usr/bin/env node
const commandLineArgs = require('command-line-args');
const path = require('path');
const cors = require("cors");

@@ -24,4 +25,4 @@ const polka = require("polka");

config.trust = config.trust || 'http://localhost:8080/certificate';
config.identity = config.identity || 'localhost-' + config.port;
config.root = config.root || process.cwd();
config.identity = config.identity || 'localhost~' + config.port;
config.root = path.resolve(process.cwd(), config.root || '.');

@@ -36,5 +37,8 @@ // TODO: RegEx check and warn for user and identity

const helpers = (req, res, next) => {
res.json = resp => res.end(JSON.stringify(resp));
res.json = resp => {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(resp));
}
res.error = (error, status = 500) => {
res.status = status;
res.statusCode = status;
res.json({

@@ -48,3 +52,7 @@ error

fetch(config.trust).then(r => r.text()).then(cert => {
fetch(config.trust).then(r => {
if (r.ok) return r.text();
throw new Error(`${r.status} ${r.statusText}`);
}).then(cert => {
console.log("Successfully fetched authorization server's certificate: " + cert);

@@ -54,2 +62,6 @@ const publicKey = ec.keyFromPublic(cert);

const auth = handler => (req, res) => {
if (!req.headers.authorization) {
return res.error('No authorization header', 403);
}
const [user, fp, signature] = req.headers.authorization.split(',');

@@ -63,3 +75,3 @@ if (user !== config.user || fp !== config.identity || !publicKey.verify({ user, fp }, signature)) {

polka()
.use(helpers, json(), cors())
.use(json(), helpers, cors())
.use('/resource', auth(serveFiles(config.root)))

@@ -70,3 +82,4 @@ .get('/identity', (_, res) => res.end(config.identity))

console.log(`> Running on localhost:${config.port}`);
console.log('Serving ' + config.root);
});
});
{
"name": "ellx",
"version": "0.0.5",
"version": "0.1.0",
"description": "ELLX resource server",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -1,2 +0,9 @@

# ellx-rs
ELLX resource server
# ellx resource server API
Path | Parameters | Description
--- | --- | ---
GET `/identity` | <none> | retrieve the identity of the server (default: localhost-port)
GET `/resource/:path` | <none> | retrieve the resource (a file or a folder index)
POST `/resource/:path` | `action (move/copy), destination` | move or copy the resource
DELETE `/resource/:path`| <none> | delete the resource
PUT `/resource/:folderPath`| `files: [[path, contents]]` | create or update multiple files or folders

@@ -1,33 +0,15 @@

const path = require('path');
const { join } = require('path');
const fs = require('fs');
const mime = require('mime/lite');
const { stat, readdir, mkdir, writeFile, rmdir, unlink, rename, copyFile } = fs.promises;
const { stat, readFile, readdir, mkdir, writeFile, rmdir, unlink, rename, copyFile } = fs.promises;
async function sendFile(req, res, file, stats, headers={}) {
let code=200, opts={};
async function sendFile(res, file, stats) {
const headers = {
'Content-Length': stats.size,
'Content-Type': 'text/plain' //mime.getType(file)
};
if (req.headers.range) {
code = 206;
let [x, y] = req.headers.range.replace('bytes=', '').split('-');
let end = opts.end = parseInt(y, 10) || stats.size - 1;
let start = opts.start = parseInt(x, 10) || 0;
if (start >= stats.size || end >= stats.size) {
res.setHeader('Content-Range', `bytes */${stats.size}`);
res.statusCode = 416;
return res.end();
}
headers['Content-Range'] = `bytes ${start}-${end}/${stats.size}`;
headers['Content-Length'] = (end - start + 1);
headers['Accept-Ranges'] = 'bytes';
}
else headers['Content-Length'] = stats.size;
headers['Content-Type'] = mime.getType(file);
headers['Last-Modified'] = stats.mtime.toUTCString();
res.writeHead(code, headers);
fs.createReadStream(file, opts).pipe(res);
res.writeHead(200, headers);
res.end(await readFile(file, { encoding: 'utf8' }));
}

@@ -40,6 +22,4 @@

.filter(item => !item.name.startsWith('.') && (item.isDirectory() || item.isFile()))
.map(item => ({
name: item.name,
type: item.isFile() ? 'file' : 'dir'
})));
.map(item => item.name + (item.isDirectory() ? '/' : ''))
);
}

@@ -50,7 +30,39 @@

const items = await readdir(filePath, { withFileTypes: true });
await Promise.all(items.map(item => (item.isDirectory() ? copyDirectory : copyFile)(path.join(filePath, item.name), path.join(newPath, item.name))));
return Promise.all(items
.map(item => (item.isDirectory() ? copyDirectory : copyFile)(
join(filePath, item.name),
join(newPath, item.name)
)));
}
async function makeOne(filePath, contents, secondTry = false) {
try {
// TODO: set proper access rights mode
if (filePath.endsWith('/')) await mkdir(filePath);
else await writeFile(filePath, contents, 'utf8');
}
catch (e) {
if (e.code === 'ENOENT') {
if (secondTry) throw e;
await makeOne(join(filePath, '../'));
return makeOne(filePath, contents, true);
}
if (e.code !== 'EEXIST') throw e;
}
}
function makeResources(filePath, files) {
files = new Map(files
.filter(Array.isArray)
.map(([path, contents]) => [join(filePath, decodeURI(path)), contents && String(contents)])
.filter(([path]) => path.startsWith(filePath))
);
return Promise.all([...files].map(pair => makeOne(...pair)));
}
const serve = root => async (req, res) => {
const filePath = path.join(root, req.path);
const filePath = join(root, decodeURI(req.path));
console.log(req.method + ' ' + filePath);

@@ -67,29 +79,26 @@ if (Object.keys(req.body).length) console.log(req.body);

if (req.method === 'GET') {
// TODO: cache everything and invalidate in fs watch
if (stats.isDirectory()) return sendDirectory(res, filePath);
else if (stats.isFile()) return sendFile(req, res, filePath, stats);
if (stats.isDirectory()) await sendDirectory(res, filePath);
else if (stats.isFile()) await sendFile(res, filePath, stats);
else return res.error('Unsupported resource type', 400);
}
else if (req.method === 'PUT') {
if (!stats.isDirectory()) return res.error('Not a directory', 400);
const { files } = req.body;
if (!stats.isDirectory()) return res.error(`${filePath} is not a directory`, 400);
if (!Array.isArray(files)) return res.error('Bad files argument', 400);
const { name, type, contents } = req.body;
const file = path.join(filePath, name);
// TODO: set proper access rights mode
if (type === 'directory') await mkdir(file);
else await writeFile(file, contents);
await makeResources(filePath, files);
}
else if (req.method === 'DELETE') {
if (stats.isDirectory()) await rmdir(filePath, { recursive: Boolean(req.body.recursive) });
if (stats.isDirectory()) await rmdir(filePath, { recursive: true });
else await unlink(filePath);
}
else if (req.method === 'POST') {
const { action, destination, recursive } = req.body;
if (stats.isDirectory() && !recursive) return res.error('To move/copy a directory you need to set recursive: true', 400);
const { action, destination } = req.body;
const newPath = path.join(root, destination);
const newPath = join(root, decodeURI(destination));
if (!newPath.startsWith(root)) return res.error('Unauthorized', 401);
if (action === 'move') await rename(filePath, newPath);
if (action === 'move') {
await rename(filePath, newPath);
}
else if (action === 'copy') {

@@ -106,3 +115,4 @@ if (stats.isDirectory()) await copyDirectory(filePath, newPath);

catch (e) {
res.error(e.code, 400);
if (e.code === 'ENOENT') res.error('Not found', 404);
else res.error(e.code, 400);
}

@@ -109,0 +119,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc