diff --git a/editions/multiwikiserver/tiddlywiki.info b/editions/multiwikiserver/tiddlywiki.info
index 1c9a935b9..94a6717e6 100644
--- a/editions/multiwikiserver/tiddlywiki.info
+++ b/editions/multiwikiserver/tiddlywiki.info
@@ -4,8 +4,7 @@
"tiddlywiki/tiddlyweb",
"tiddlywiki/filesystem",
"tiddlywiki/multiwikiclient",
- "tiddlywiki/multiwikiserver",
- "tiddlywiki/authentication"
+ "tiddlywiki/multiwikiserver"
],
"themes": [
"tiddlywiki/vanilla",
diff --git a/plugins/tiddlywiki/authentication/plugin.info b/plugins/tiddlywiki/authentication/plugin.info
deleted file mode 100644
index 241370a36..000000000
--- a/plugins/tiddlywiki/authentication/plugin.info
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "title": "$:/plugins/tiddlywiki/authentication",
- "description": "Authentication plugin for TiddlyWiki",
- "author": "Anon",
- "version": "0.1.0",
- "core-version": ">=5.0.0",
- "plugin-type": "plugin",
- "list": ["login"]
-}
\ No newline at end of file
diff --git a/plugins/tiddlywiki/multiwikiserver/auth/form/login.tid b/plugins/tiddlywiki/multiwikiserver/auth/form/login.tid
new file mode 100644
index 000000000..a1923b8ca
--- /dev/null
+++ b/plugins/tiddlywiki/multiwikiserver/auth/form/login.tid
@@ -0,0 +1,19 @@
+title: $:/plugins/tiddlywiki/multiwikiserver/auth/form/login
+tags: $:/tags/ServerRoute
+route-method: GET
+route-path: /login
+
+<$transclude tiddler="$:/plugins/tiddlywiki/multiwikiserver/auth/form/login/styles"/>
+
+
+
+ <$transclude tiddler="$:/plugins/tiddlywiki/multiwikiserver/auth/form/login/head"/>
+
+
+
+ <$transclude tiddler="$:/plugins/tiddlywiki/multiwikiserver/auth/form/login/header" mode="block"/>
+ <$transclude tiddler="$:/plugins/tiddlywiki/multiwikiserver/auth/form/login/form" mode="block"/>
+ <$transclude tiddler="$:/plugins/tiddlywiki/multiwikiserver/auth/form/login/error-message" mode="block"/>
+
+
+
\ No newline at end of file
diff --git a/plugins/tiddlywiki/multiwikiserver/auth/form/login/error-message.tid b/plugins/tiddlywiki/multiwikiserver/auth/form/login/error-message.tid
new file mode 100644
index 000000000..372e7c8f1
--- /dev/null
+++ b/plugins/tiddlywiki/multiwikiserver/auth/form/login/error-message.tid
@@ -0,0 +1,7 @@
+title: $:/plugins/tiddlywiki/multiwikiserver/auth/form/login/error-message
+
+<$list filter="[[$:/temp/mws/login/error]!is[missing]]" variable="errorTiddler">
+
+ {{$:/temp/mws/login/error}}
+
+$list>
\ No newline at end of file
diff --git a/plugins/tiddlywiki/multiwikiserver/auth/form/login/form.tid b/plugins/tiddlywiki/multiwikiserver/auth/form/login/form.tid
new file mode 100644
index 000000000..93d6ca773
--- /dev/null
+++ b/plugins/tiddlywiki/multiwikiserver/auth/form/login/form.tid
@@ -0,0 +1,10 @@
+title: $:/plugins/tiddlywiki/multiwikiserver/auth/form/login/form
+
+
+<$macrocall $name="loginForm"/>
+
diff --git a/plugins/tiddlywiki/multiwikiserver/auth/form/login/head.tid b/plugins/tiddlywiki/multiwikiserver/auth/form/login/head.tid
new file mode 100644
index 000000000..b5df2aa5a
--- /dev/null
+++ b/plugins/tiddlywiki/multiwikiserver/auth/form/login/head.tid
@@ -0,0 +1,3 @@
+title: $:/plugins/tiddlywiki/multiwikiserver/auth/form/login/head
+
+TiddlyWiki Login
\ No newline at end of file
diff --git a/plugins/tiddlywiki/multiwikiserver/auth/form/login/header.tid b/plugins/tiddlywiki/multiwikiserver/auth/form/login/header.tid
new file mode 100644
index 000000000..d6e75df8e
--- /dev/null
+++ b/plugins/tiddlywiki/multiwikiserver/auth/form/login/header.tid
@@ -0,0 +1,3 @@
+title: $:/plugins/tiddlywiki/multiwikiserver/auth/form/login/header
+
+TiddlyWiki Login
\ No newline at end of file
diff --git a/plugins/tiddlywiki/authentication/tiddlers/login.tid b/plugins/tiddlywiki/multiwikiserver/auth/form/login/styles.tid
similarity index 50%
rename from plugins/tiddlywiki/authentication/tiddlers/login.tid
rename to plugins/tiddlywiki/multiwikiserver/auth/form/login/styles.tid
index 5294a7e0f..1d633c459 100644
--- a/plugins/tiddlywiki/authentication/tiddlers/login.tid
+++ b/plugins/tiddlywiki/multiwikiserver/auth/form/login/styles.tid
@@ -1,19 +1,5 @@
-title: $:/plugins/tiddlywiki/authentication/login
-tags: $:/tags/ServerRoute
-route-method: GET
-route-path: /login
+title: $:/plugins/tiddlywiki/multiwikiserver/auth/form/login/styles
-\define loginForm()
-
-\end
-
-
-
-
-
-
-
TiddlyWiki Login
- <$set name="returnUrl" value={{{ [{$:/temp/mws/login/returnUrl}!is[blank]else{$:/info/url/query}split[returnUrl=]last[]else[/]] }}}>
- <
>
- $set>
- <$list filter="[[$:/temp/mws/login/error]!is[missing]]" variable="errorTiddler">
-
- {{$:/temp/mws/login/error}}
-
- $list>
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/plugins/tiddlywiki/multiwikiserver/modules/mws-server.js b/plugins/tiddlywiki/multiwikiserver/modules/mws-server.js
index e4ffd05b7..922da7c2c 100644
--- a/plugins/tiddlywiki/multiwikiserver/modules/mws-server.js
+++ b/plugins/tiddlywiki/multiwikiserver/modules/mws-server.js
@@ -77,8 +77,6 @@ function Server(options) {
$tw.modules.forEachModuleOfType("mws-route", function(title,routeDefinition) {
self.addRoute(routeDefinition);
});
- // Load tiddler-based routes
- self.loadAuthRoutes();
// Initialise the http vs https
this.listenOptions = null;
this.protocol = "http";
@@ -304,88 +302,6 @@ Server.prototype.addRoute = function(route) {
this.routes.push(route);
};
-Server.prototype.loadAuthRoutes = function () {
- var self = this;
- // add the login page route
- self.addRoute({
- method: "GET",
- path: /^\/login$/,
- handler: function (request, response, state) {
- // Check if the user already has a valid session
- const authenticatedUser = self.authenticateUser(request, response);
- if (authenticatedUser) {
- // User is already logged in, redirect to home page
- response.writeHead(302, { 'Location': '/' });
- response.end();
- return;
- }
- var loginTiddler = self.wiki.getTiddler("$:/plugins/tiddlywiki/authentication/login");
- if (loginTiddler) {
- var text = self.wiki.renderTiddler("text/html", loginTiddler.fields.title);
- response.writeHead(200, { "Content-Type": "text/html" });
- response.end(text);
- } else {
- response.writeHead(404);
- response.end("Login page not found");
- }
- }
- });
- // add the login submission handler route
- self.addRoute({
- method: "POST",
- path: /^\/login$/,
- csrfDisable: true,
- handler: function(request, response, state) {
- self.handleLogin(request, response, state);
- }.bind(self)
- });
- self.addRoute({
- method: "POST",
- path: /^\/logout$/,
- csrfDisable: true,
- handler: function(request, response, state) {
- self.handleLogout(request, response, state);
- }.bind(self)
- });
-};
-
-Server.prototype.handleLogout = function (request, response, state) {
- var self = this;
- if (state.authenticatedUser) {
- self.sqlTiddlerDatabase.deleteSession(state.authenticatedUser.sessionId);
- }
- response.setHeader('Set-Cookie', 'session=; HttpOnly; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT');
- response.writeHead(302, { 'Location': '/login' });
- response.end();
-}
-
-Server.prototype.handleLogin = function (request, response, state) {
- var self = this;
- const querystring = require('querystring');
- const formData = querystring.parse(state.data);
- const { username, password } = formData;
- const user = self.sqlTiddlerDatabase.getUserByUsername(username);
- const isPasswordValid = self.verifyPassword(password, user?.password)
-
- if (user && isPasswordValid) {
- const sessionId = self.createSession(user.user_id);
- const {returnUrl} = this.parseCookieString(request.headers.cookie)
- response.setHeader('Set-Cookie', `session=${sessionId}; HttpOnly; Path=/`);
- response.writeHead(302, {
- 'Location': returnUrl || '/'
- });
- } else {
- this.wiki.addTiddler(new $tw.Tiddler({
- title: "$:/temp/mws/login/error",
- text: "Invalid username or password"
- }));
- response.writeHead(302, {
- 'Location': '/login'
- });
- }
- response.end();
-};
-
Server.prototype.verifyPassword = function(inputPassword, storedHash) {
const hashedInput = this.hashPassword(inputPassword);
return hashedInput === storedHash;
diff --git a/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/get-login.js b/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/get-login.js
new file mode 100644
index 000000000..dd0421a66
--- /dev/null
+++ b/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/get-login.js
@@ -0,0 +1,39 @@
+/*\
+title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/get-login.js
+type: application/javascript
+module-type: mws-route
+
+GET /login
+
+\*/
+(function() {
+
+/*jslint node: true, browser: true */
+/*global $tw: false */
+"use strict";
+
+exports.method = "GET";
+
+exports.path = /^\/login$/;
+
+exports.handler = function(request,response,state) {
+ // Check if the user already has a valid session
+ var authenticatedUser = state.server.authenticateUser(request, response);
+ if(authenticatedUser) {
+ // User is already logged in, redirect to home page
+ response.writeHead(302, { "Location": "/" });
+ response.end();
+ return;
+ }
+ var loginTiddler = $tw.mws.store.adminWiki.getTiddler("$:/plugins/tiddlywiki/multiwikiserver/auth/form/login");
+ if(loginTiddler) {
+ var text = $tw.mws.store.adminWiki.renderTiddler("text/html", loginTiddler.fields.title);
+ response.writeHead(200, { "Content-Type": "text/html" });
+ response.end(text);
+ } else {
+ response.writeHead(404);
+ response.end("Login page not found");
+ }
+};
+
+}());
diff --git a/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/get-users.js b/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/get-users.js
new file mode 100644
index 000000000..fea50ba19
--- /dev/null
+++ b/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/get-users.js
@@ -0,0 +1,54 @@
+/*\
+title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/get-users.js
+type: application/javascript
+module-type: mws-route
+
+GET /admin/users
+
+\*/
+(function() {
+
+ /*jslint node: true, browser: true */
+ /*global $tw: false */
+ "use strict";
+
+ exports.method = "GET";
+
+ exports.path = /^\/admin\/users$/;
+
+ exports.handler = function(request,response,state) {
+ var userList = state.server.sqlTiddlerDatabase.listUsers();
+
+ // Ensure userList is an array
+ if (!Array.isArray(userList)) {
+ userList = [];
+ console.error("userList is not an array");
+ }
+
+ // Convert dates to strings and ensure all necessary fields are present
+ userList = userList.map(user => ({
+ user_id: user.user_id || '',
+ username: user.username || '',
+ email: user.email || '',
+ created_at: user.created_at ? new Date(user.created_at).toISOString() : '',
+ last_login: user.last_login ? new Date(user.last_login).toISOString() : ''
+ }));
+
+ console.log("Processed userList =>", userList);
+
+ response.writeHead(200, "OK", {
+ "Content-Type": "text/html"
+ });
+
+ // Render the html
+ var html = $tw.mws.store.adminWiki.renderTiddler("text/plain","$:/plugins/tiddlywiki/multiwikiserver/templates/page",{
+ variables: {
+ "page-content": "$:/plugins/tiddlywiki/multiwikiserver/templates/get-users",
+ "user-list": JSON.stringify(userList),
+ }
+ });
+ response.write(html);
+ response.end();
+ };
+
+ }());
\ No newline at end of file
diff --git a/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/post-login.js b/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/post-login.js
new file mode 100644
index 000000000..0df0dd003
--- /dev/null
+++ b/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/post-login.js
@@ -0,0 +1,53 @@
+/*\
+title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/post-login.js
+type: application/javascript
+module-type: mws-route
+
+POST /login
+
+Parameters:
+
+username
+password
+
+\*/
+(function() {
+
+/*jslint node: true, browser: true */
+/*global $tw: false */
+"use strict";
+
+exports.method = "POST";
+
+exports.path = /^\/login$/;
+
+exports.bodyFormat = "www-form-urlencoded";
+
+exports.csrfDisable = true;
+
+exports.handler = function(request,response,state) {
+ var username = state.data.username;
+ var password = state.data.password;
+ var user = state.server.sqlTiddlerDatabase.getUserByUsername(username);
+ var isPasswordValid = state.server.verifyPassword(password, user ? user.password : null)
+
+ if(user && isPasswordValid) {
+ var sessionId = state.server.createSession(user.user_id);
+ var returnUrl = state.server.parseCookieString(request.headers.cookie).returnUrl
+ response.setHeader('Set-Cookie', `session=${sessionId}; HttpOnly; Path=/`);
+ response.writeHead(302, {
+ 'Location': returnUrl || '/'
+ });
+ } else {
+ $tw.mws.store.adminWiki.addTiddler(new $tw.Tiddler({
+ title: "$:/temp/mws/login/error",
+ text: "Invalid username or password"
+ }));
+ response.writeHead(302, {
+ 'Location': '/login'
+ });
+ }
+ response.end();
+};
+
+}());
diff --git a/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/post-logout.js b/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/post-logout.js
new file mode 100644
index 000000000..423ddf3bc
--- /dev/null
+++ b/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/post-logout.js
@@ -0,0 +1,30 @@
+/*\
+title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/post-logout.js
+type: application/javascript
+module-type: mws-route
+
+POST /logout
+
+\*/
+(function() {
+
+/*jslint node: true, browser: true */
+/*global $tw: false */
+"use strict";
+
+exports.method = "POST";
+
+exports.path = /^\/logout$/;
+
+exports.csrfDisable = true;
+
+exports.handler = function(request,response,state) {
+ if(state.authenticatedUser) {
+ state.server.sqlTiddlerDatabase.deleteSession(state.authenticatedUser.sessionId);
+ }
+ response.setHeader("Set-Cookie", "session=; HttpOnly; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT");
+ response.writeHead(302, { "Location": "/login" });
+ response.end();
+};
+
+}());
diff --git a/plugins/tiddlywiki/multiwikiserver/templates/get-users.tid b/plugins/tiddlywiki/multiwikiserver/templates/get-users.tid
new file mode 100644
index 000000000..310312d61
--- /dev/null
+++ b/plugins/tiddlywiki/multiwikiserver/templates/get-users.tid
@@ -0,0 +1,89 @@
+
+
+\define lingo-base() $:/language/ControlPanel/Tools/
+
+User Management
+
+
+Debug Info
+Raw user list JSON: <$text text=<>/>
+
+
+<$set name="userList" value=<>>
+
+ <$list filter="[!is[blank]]" emptyMessage="The user list is empty or not provided.">
+ User list found: <$text text=<>/>
+
+
+ <$set name="parsedUserList" value={{{ [jsonparse[]] }}}/>
+
+
+ <$list filter="[count[]compare:number:gt[0]]" emptyMessage="No users found or failed to parse user data">
+
+ Parsed User List (as JSON): <$text text={{{ [jsonstringify[]] }}}/>
+
+
+ Total users: <$text text={{{ [count[]] }}}/>
+
+
+
+
+
+ Username |
+ Email |
+ Created At |
+ Last Login |
+ Actions |
+
+
+
+ <$list filter="[jsonindexes[]]" variable="userIndex">
+ <$let currentUser={{{ [jsonget] }}}>
+
+ <$text text={{{ [jsonget[username]] }}}/> |
+ <$text text={{{ [jsonget[email]] }}}/> |
+ <$text text={{{ [jsonget[created_at]] }}}/> |
+ <$text text={{{ [jsonget[last_login]] }}}/> |
+
+ <$button message="tm-server-command" param="edit-user" user_id={{{ [jsonget[user_id]] }}} class="tc-btn-invisible">
+ {{$:/core/images/edit-button}} Edit
+ $button>
+ <$button message="tm-server-command" param="delete-user" user_id={{{ [jsonget[user_id]] }}} class="tc-btn-invisible">
+ {{$:/core/images/delete-button}} Delete
+ $button>
+ |
+
+ $let>
+ $list>
+
+
+ $list>
+ $list>
+$set>
+
+<$button message="tm-modal" param="$:/plugins/tiddlywiki/multiwikiserver/templates/add-user-modal" class="tc-btn-big-green">
+Add New User
+$button>
+
+