1
0
mirror of https://github.com/falk-werner/webfuse-provider synced 2026-03-02 04:09:18 +00:00

feat(webfuse): add multiclient support (#23)

* fixes verbosity option when set through command line

* adds support for build type and allows to run gdb in container

* adds missing toolchain headers to project

* renames container macros

* adds gdbserver

* fixes verbosity option when set through command line

* adds support for build type and allows to run gdb in container

* adds missing toolchain headers to project

* renames container macros

* adds gdbserver

* removes language settings, which contains alternating values

* adds wrapper script to launch gdbserver

* fix docker command in wrapper script

* fixes run in dind setup

* replaces docker's init through dump-init

* moves filesystem to session

* fixes verbosity option when set through command line

* adds support for build type and allows to run gdb in container

* renames container macros

* adds gdbserver

* fixes verbosity option when set through command line

* adds support for build type and allows to run gdb in container

* renames container macros

* adds gdbserver

* adds wrapper script to launch gdbserver

* fix docker command in wrapper script

* fixes run in dind setup

* replaces docker's init through dump-init

* moves filesystem to session

* adds container_of

* added dlist

* allows multiple clients to connect

* removes directory when session is closed

* adds dependecy to uuid-dev

* allow clients to register filesystems

* updates documentation

* moves mountpoint handling into filesystem: mountpoints are removed during session cleanup

* adds filesystem name/id to request parameters

* fixes security issue: add_filesystem did not check name

* removes default link, if it is broken

* recreates symlink "default", if filesystem is gone

* updates documentation

* fixes memory leak

* makes authentication work .. again

* updates provider to support changed protocol

* removes execute right of hello.txt

* fixes style issues

* fixes javascript style issues

* fixes flase positive from Flawfinder

* fixes some javascript style issues

* removes use of PATH_MAX

* removes use of GNU extensions in container_of implementation

* ignores findings of flawfinder

* replaces dlist by slist

* removes duplicate implementation of slist (message_queue)
This commit is contained in:
Falk Werner
2019-04-17 22:51:16 +02:00
committed by nosamad
parent 979ff1e689
commit 3a7c064af7
52 changed files with 997 additions and 337 deletions

View File

@@ -50,13 +50,14 @@ static bool authenticate(struct wf_credentials * creds, void * user_data)
char const * password = wf_credentials_get(creds, "password");
if ((NULL != username) && (NULL != password))
{
struct userdb * db = userdb_create("<pepper>");
struct userdb * db = userdb_create("");
result = userdb_load(db, args->passwd_path);
if (result)
{
result = userdb_check(db, username, password);
userdb_dispose(db);
}
userdb_dispose(db);
}
return result;

View File

@@ -1,5 +1,6 @@
export class ConnectionView {
constructor(client) {
constructor(client, provider) {
this._provider = provider;
this._client = client;
this._client.onopen = () => { this._onConnectionOpened(); };
this._client.onclose = () => { this._onConnectionClosed(); };
@@ -28,6 +29,14 @@ export class ConnectionView {
const authenticateBox = document.createElement("div");
this.element.appendChild(authenticateBox);
const authLabel = document.createElement("span");
authLabel.textContent = "use authentication:";
authenticateBox.appendChild(authLabel);
this.authenticateCheckbox = document.createElement("input");
this.authenticateCheckbox.type = "checkbox";
authenticateBox.appendChild(this.authenticateCheckbox);
const usernameLabel = document.createElement("span");
usernameLabel.textContent = "user:";
authenticateBox.appendChild(usernameLabel);
@@ -45,12 +54,6 @@ export class ConnectionView {
this.passwordTextbox.type = "password";
this.passwordTextbox.value = "secret";
authenticateBox.appendChild(this.passwordTextbox);
this.authenticateButton = document.createElement("input");
this.authenticateButton.type = "button";
this.authenticateButton.value = "authenticate";
this.authenticateButton.addEventListener("click", () => { this._onAuthenticateButtonClicked(); });
authenticateBox.appendChild(this.authenticateButton);
}
_onConnectButtonClicked() {
@@ -65,14 +68,21 @@ export class ConnectionView {
_onAuthenticateButtonClicked() {
if (this._client.isConnected()) {
const username = this.usernameTextbox.value;
const password = this.passwordTextbox.value;
this._client.authenticate("username", { username, password });
}
}
_onConnectionOpened() {
if (this.authenticateCheckbox.checked) {
const username = this.usernameTextbox.value;
const password = this.passwordTextbox.value;
const promise = this._client.authenticate("username", { username, password });
promise.then(() => { this._client.addProvider("test", this._provider); });
} else {
this._client.addProvider("test", this._provider);
}
this.connectButton.value = "disconnect";
}

View File

@@ -17,8 +17,8 @@ function startup() {
"say_hello.sh": { inode: 3, mode: mode("0555"), type: "file", contents: "#!/bin/sh\necho hello\n"}
}
});
const client = new Client(provider);
const connectionView = new ConnectionView(client);
const client = new Client();
const connectionView = new ConnectionView(client, provider);
document.getElementById('connection').appendChild(connectionView.element);
}

View File

@@ -4,7 +4,9 @@ export class Client {
static get _PROTOCOL() { return "fs"; }
constructor(provider) {
this._provider = provider;
this._provider = { };
this._pendingRequests = {};
this._id = 0;
this._ws = null;
this.onopen = () => { };
this.onclose = () => { };
@@ -24,11 +26,27 @@ export class Client {
};
}
_invokeRequest(method, params) {
this._id += 1;
const id = this._id;
const request = {method, params, id};
return new Promise((resolve, reject) => {
this._pendingRequests[id] = {resolve, reject};
this._ws.send(JSON.stringify(request));
});
}
authenticate(type, credentials) {
return this._invokeRequest("authenticate", [type, credentials]);
}
addProvider(name, provider) {
this._provider[name] = provider;
const request = {
"method": "authenticate",
"params": [type, credentials],
"id": 42
"method": "add_filesystem",
"params": [name],
"id": 23
};
this._ws.send(JSON.stringify(request));
@@ -45,27 +63,61 @@ export class Client {
return ((this._ws) && (this._ws.readyState === WebSocket.OPEN));
}
_isRequest(request) {
const method = request.method;
return (("string" === typeof(method)) && ("params" in request));
}
_isResponse(response) {
const id = response.id;
return (("number" === typeof(id)) && (("result" in response) || ("error" in response)));
}
_removePendingRequest(id) {
let result = null;
if (id in this._pendingRequests) {
result = this._pendingRequests[id];
Reflect.deleteProperty(this._pendingRequests, id);
}
return result;
}
_onmessage(message) {
try {
const request = JSON.parse(message.data);
const method = request.method;
const id = request.id;
const params = request.params;
const data = JSON.parse(message.data);
if ("string" !== typeof(method)) {
throw new Error("parse error: missing field: \"method\"");
if (this._isRequest(data)) {
const method = data.method;
const id = data.id;
const params = data.params;
if ("number" === typeof(id)) {
this._invoke(method, params, id);
}
else {
this._notify(method, params);
}
}
else if (this._isResponse(data)) {
const id = data.id;
const result = data.result;
const error = data.error;
const request = this._removePendingRequest(id);
if (request) {
if (result) {
request.resolve(result);
}
else {
request.reject(error);
}
}
}
if (!params) {
throw new Error("parse error: missing field: \"params\"");
}
if ("number" === typeof(request.id)) {
this._invoke(method, params, id);
}
else {
this._notify(method, params);
}
}
catch (ex) {
// swallow
@@ -114,28 +166,48 @@ export class Client {
}
}
async _lookup([parent, name]) {
return this._provider.lookup(parent, name);
_getProvider(name) {
if (name in this._provider) {
return this._provider[name];
}
else {
throw new Error('Unknown provider');
}
}
async _getattr([inode]) {
return this._provider.getattr(inode);
async _lookup([providerName, parent, name]) {
const provider = this._getProvider(providerName);
return provider.lookup(parent, name);
}
async _readdir([inode]) {
return this._provider.readdir(inode);
async _getattr([providerName, inode]) {
const provider = this._getProvider(providerName);
return provider.getattr(inode);
}
async _open([inode, mode]) {
return this._provider.open(inode, mode);
async _readdir([providerName, inode]) {
const provider = this._getProvider(providerName);
return provider.readdir(inode);
}
_close([inode, handle, mode]) {
this._provider.close(inode, handle, mode);
async _open([providerName, inode, mode]) {
const provider = this._getProvider(providerName);
return provider.open(inode, mode);
}
async _read([inode, handle, offset, length]) {
const data = await this._provider.read(inode, handle, offset, length);
_close([providerName, inode, handle, mode]) {
const provider = this._getProvider(providerName);
provider.close(inode, handle, mode);
}
async _read([providerName, inode, handle, offset, length]) {
const provider = this._getProvider(providerName);
const data = await provider.read(inode, handle, offset, length);
if ("string" === typeof(data)) {
return {

View File

@@ -340,7 +340,7 @@ int main(int argc, char* argv[])
.parent = 1,
.inode = 2,
.name = "hello.txt",
.mode = 0555,
.mode = 0444,
.type = FS_FILE,
.content="hello, world!",
.content_length = 13,