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:
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user