Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mws authentication #8596

Merged

Conversation

webplusai
Copy link
Contributor

No description provided.

Copy link

stackblitz bot commented Sep 12, 2024

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

Copy link

Confirmed: webplusai has already signed the Contributor License Agreement (see contributing.md)

@Jermolene
Copy link
Member

Thank you @webplusai this is looking good. I will provide some detailed feedback shortly.

@joshuafontany
Copy link
Contributor

Following along (very busy at work atm, company is reorging... again). This is exciting stuff!

Copy link
Member

@Jermolene Jermolene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @webplusai this is looking good. There is what looks like some work-in-progress areas such as handleLogin. It makes a lot of sense to keep things simple there temporarily, and so I would like to merge this. However I think it may just be worth you adding comments to tag the TODO areas to make explicit the areas that we need to revisit.

plugins/tiddlywiki/authentication/tiddlers/login.tid Outdated Show resolved Hide resolved
plugins/tiddlywiki/authentication/plugin.info Outdated Show resolved Hide resolved
Copy link
Member

@Jermolene Jermolene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @webplusai that's great. I think the best way forwards now is to merge this and discuss further refinements. However at the moment the tests are failing, if you could kindly fix them up then I'll go ahead and merge.

@webplusai
Copy link
Contributor Author

@Jermolene I've fixed the test issue. Also some issues that I had related to the user list and roles were also fixed.

@Jermolene
Copy link
Member

Thank you @webplusai. As discussed I am keen to get this merged. There are some points I would like to return to but we can worry about those later.

I think the blocker now is that we've got users who are testing the multi-wiki-support branch, and it is going to be a bad experience for them if they upgrade and then are presented with a login dialogue, with no obvious way to create or access a user account.

Ideally, we should get to the point where by default the user gets the previous experience of anonymous read/write access, with an obvious route to get to an admin screen so that they can enable password access and try things out.

One possibility would be to add commands like --mws-add-user, --mws-list-users etc. and use them to set up a demo configuration in a new npm command.

Let me know if that makes sense, ideally we should discuss the details before spending too much time on implementation.

@webplusai
Copy link
Contributor Author

@Jermolene I've added the commands as you indicated.

Copy link
Member

@pmario pmario left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did only have a closer look at the code, where I did add some comments. I will have a closer look soon.

return "Usage: --mws-add-user <username> <password> [email]";
}

if(!$tw.mws || !$tw.mws.store || !$tw.mws.store.sqlTiddlerDatabase) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the usernames and passwords should never be stored with the content. So for me !$tw.mws.store.sqlTiddlerDatabase looks like it is in the same database file?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @pmario I think it's perfectly OK for this data to be in the same database. There's no more obvious way for queries of the tiddler database to accidentally start returning results from the user database than there is for any data corruption within a program.

What I do want to pay attention to is the best practice of making the admin UI run off of a different HTTP host/port, so that administrators can use external tools to lock down admin access.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this will prevent us from using different authentication and authorisation services / mechanisms in the future.

Using Usernames and passwords is notoriously unsecure and imo outdated already today. The minimal requirement I would consider somewhat save is username/password in a combination with a time based 2-factor-code generated with an authenticator app.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plan is to have pluggable authentication schemes. Form-based authentication is still pretty standard for website logins and so I don't think we can avoid offering it, but I definitely want to support things like logging in with Google or GitHub credentials.


var username = this.params[0];
var password = this.params[1];
var email = this.params[2] || username + "@tiddlywiki.com";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If username + @tiddlywiki.com is a placeholder, imo it should be example.com -- Otherwise it means, that tiddlywiki.com also provided an email-service. Which is not the case

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps use example.com for the moment?

var username = this.params[0];
var password = this.params[1];
var email = this.params[2] || username + "@tiddlywiki.com";
var hashedPassword = crypto.createHash("sha256").update(password).digest("hex");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simple sha256 hashing the password is not enough. The password needs to be salted and then encrypted at least 10000 times. Key-stretching makes it harder to use rainbow-tables and brute force password attacks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm comfortable with having a placeholder implementation to begin with. At this point, I think clarity is the most important consideration, and with adequate encapsulation it will be straightforward for us to revisit the implementation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is, that it should be done right from the beginning, because the salt has to be stored with the user data. It also plays into the login form. So there are at least 3 different positions, where a change here causes changes up to the UI password handling.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pmario the challenge is that we need to merge this PR to get feedback. If we wait until we've got a production ready authentication system then this PR would have to stay open for a long time, making all other work on MWS much more complicated. At this point we have the freedom that if required MWS can nuke the user database on an upgrade. We will lose that freedom as MWS moves beyond the experimental stage, so we should take advantage of it now to improve our overall velocity.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

@pmario
Copy link
Member

pmario commented Oct 2, 2024

@webplusai ... Is there some description which mechanisms are used with the whole authentication system?

@Jermolene ... As I wrote sensible data should not be part of the same database as the content. They should be completely separated. IMO this will also help to use other systems that provide secure vaults in the future.

@pmario
Copy link
Member

pmario commented Oct 2, 2024

  • I did run: npm run mws-add-user
  • Then I did run npm start

Is this order right, or did I do it wrong?

Which does start the server and I do get the user UI. But if I try to create a new bag, I do get a server-runtime error

grafik

syncer-server-filesystem: Dispatching 'save' task: $:/StoryList
Serving on http://127.0.0.1:8080
(press ctrl-C to exit)
$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js:31
    var partiallyDecoded = entityName.replace(/%3A/g, ":");
                                      ^

TypeError: Cannot read properties of undefined (reading 'replace')
    at exports.middleware ($:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js:31:39)
    at exports.handler ($:/plugins/tiddlywiki/multiwikiserver/routes/handlers/post-bag.js:31:2)
    at IncomingMessage.<anonymous> ($:/plugins/tiddlywiki/multiwikiserver/mws-server.js:525:10)
    at IncomingMessage.emit (node:events:519:28)
    at endReadableNT (node:internal/streams/readable:1696:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

Node.js v20.14.0
PS E:\git\tiddly\tiddlywiki\TiddlyWiki5>

@Jermolene
Copy link
Member

Thanks @webplusai

Great to have your feedback @pmario, this is a great stage to be hammering out some important details.

@@ -0,0 +1,10 @@
title: $:/plugins/tiddlywiki/multiwikiserver/auth/form/login/form
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only 1 empty line is needed after the tiddler-header

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please check all you files to use tabs for indentation.

Command to create a permission

\*/
(function(){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiddlywiki code uses tabs for indentation. Tab width = 4

The first level inside the (function(){ wrapper is not indented. So eg: export.info = ... does not need a leading tab.

@@ -301,6 +302,22 @@ Server.prototype.addRoute = function(route) {
this.routes.push(route);
};

Server.prototype.verifyPassword = function(inputPassword, storedHash) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should authentication be part of this file. IMO it should be it's own file and it should be required. So we get a clear separation of concerns. It should also help to keep the api cleaner.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's a good idea @pmario

"bag-tiddlers": JSON.stringify(bagTiddlers)
(function () {

/*jslint node: true, browser: true */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first level inside the wrapper function should not be indented. Otherwise the diff does not show, what really changed


\*/
(function() {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

});
} else {
response.writeHead(400);
(function () {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation -- please check all files

@@ -0,0 +1,123 @@
title: $:/plugins/tiddlywiki/multiwikiserver/templates/manage-roles

\define add-role-actions()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use tabs instead of spaces for indent - please check all files

@webplusai
Copy link
Contributor Author

  • I did run: npm run mws-add-user
  • Then I did run npm start

Is this order right, or did I do it wrong?

Which does start the server and I do get the user UI. But if I try to create a new bag, I do get a server-runtime error

grafik

syncer-server-filesystem: Dispatching 'save' task: $:/StoryList
Serving on http://127.0.0.1:8080
(press ctrl-C to exit)
$:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js:31
    var partiallyDecoded = entityName.replace(/%3A/g, ":");
                                      ^

TypeError: Cannot read properties of undefined (reading 'replace')
    at exports.middleware ($:/plugins/tiddlywiki/multiwikiserver/modules/routes/helpers/acl-middleware.js:31:39)
    at exports.handler ($:/plugins/tiddlywiki/multiwikiserver/routes/handlers/post-bag.js:31:2)
    at IncomingMessage.<anonymous> ($:/plugins/tiddlywiki/multiwikiserver/mws-server.js:525:10)
    at IncomingMessage.emit (node:events:519:28)
    at endReadableNT (node:internal/streams/readable:1696:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

Node.js v20.14.0
PS E:\git\tiddly\tiddlywiki\TiddlyWiki5>

@pmario you did it correct. There was an error and I fixed it.

@pmario
Copy link
Member

pmario commented Oct 15, 2024

You seem to be arguing that it is dangerous to allow users to set things up for anonymous access. I do not agree at all. Anonymous read/write access is perfectly reasonable in many scenarios, and has a long history.

As long as the servers are used on private networks only. But that's not what our users request. They request access from everywhere. So they want a simple way to connect their private servers to the internet.

Connecting servers with valuable data to the internet is dangerous. See: https://techcrunch.com/2024/10/14/2024-in-data-breaches-1-billion-stolen-records-and-rising/

Hacking vulnerable devices is simple. The Mirai botnet, where the source code is here at github, only uses 64 hardcoded passwords to hijack 600.000 devices. See: https://blog.cloudflare.com/inside-mirai-the-infamous-iot-botnet-a-retrospective-analysis/ -- IMO this is a strong proof, that users do not enable security if they are not forced to. The article at cloudflare is from 2017 and Mirai should not be a thread anymore.

It's easy to repeat catchphrases like "secure by default" but I don't think it's very useful without some critical analysis.

That's right and we should think a bit more about it. https://www.cisa.gov/resources-tools/resources/secure-by-design and https://www.cisa.gov/sites/default/files/2023-10/SecureByDesign_1025_508c.pdf

The PDF above is mainly addressing companies, but I think the principles are worth considering.

Especially in a TiddlyWiki context of education, where we are really strong: See: https://www.cisa.gov/sites/default/files/2023-08/K-12_Acquisition_Guidance.pdf (only 2 pages)

@webplusai
Copy link
Contributor Author

@Jermolene @pmario
Do we all agree to build interactive UI so that users can configure when they start the project? Or what approach would we proceed on?

@Jermolene
Copy link
Member

As long as the servers are used on private networks only. But that's not what our users request. They request access from everywhere. So they want a simple way to connect their private servers to the internet.

That is one of the things that users want. But it doesn't really advance your case.

Connecting servers with valuable data to the internet is dangerous. See: https://techcrunch.com/2024/10/14/2024-in-data-breaches-1-billion-stolen-records-and-rising/

It is also ubiquitous. I really don't see the relevance of this comment.

We're talking here about the onboarding experience of installing and setting up a new server. "Valuable data" only enters the picture once it is set up as wanted.

Hacking vulnerable devices is simple. The Mirai botnet, where the source code is here at github, only uses 64 hardcoded passwords to hijack 600.000 devices. See: https://blog.cloudflare.com/inside-mirai-the-infamous-iot-botnet-a-retrospective-analysis/ -- IMO this is a strong proof, that users do not enable security if they are not forced to. The article at cloudflare is from 2017 and Mirai should not be a thread anymore.

What is the relevance of this observation?

That's right and we should think a bit more about it. https://www.cisa.gov/resources-tools/resources/secure-by-design and https://www.cisa.gov/sites/default/files/2023-10/SecureByDesign_1025_508c.pdf

Again, what is the relevance of those PDFs to your argument?

Especially in a TiddlyWiki context of education, where we are really strong: See: https://www.cisa.gov/sites/default/files/2023-08/K-12_Acquisition_Guidance.pdf (only 2 pages)

Again, what bearing does this have on your argument.

The position at the moment is that I proposed a way forward for @webplusai and you've raised a vague concern about "security by default" without providing any actionable feedback to the proposal.

@Jermolene
Copy link
Member

@Jermolene @pmario Do we all agree to build interactive UI so that users can configure when they start the project? Or what approach would we proceed on?

I think @pmario's concerns need to be taken out of the critical path of your work. I would suggest proceeding along the lines I proposed. Remember that we're trying to do minimal work to be able to merge this with a reasonable user experience. Making it anonymous access by default matches the current configuration and so is categorically not a problem. We can't hold up merging your work until some hypothetical point has been reached, we need to be practical.

@webplusai
Copy link
Contributor Author

@Jermolene so just to confirm, we will proceed on this way. Right?
The best I can think of is an interactive wizard that kicks in at startup to ask the user how they want their server configured.

@Jermolene
Copy link
Member

@Jermolene so just to confirm, we will proceed on this way. Right? The best I can think of is an interactive wizard that kicks in at startup to ask the user how they want their server configured.

Again, we need to look at this through the lens of what is the path that allows us to merge this PR as swiftly as possible. I think it's perfectly OK for the out-of-the-box experience to be anonymous read/write access, with either a web or command line path to setting up security, whichever will be quickest to build.

By default, the Multiwiki Server starts up without authentication enabled. In order to enabled authentication, start the app using the following command:

```bash
npm run start -- --mws-use-auth
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the first -- for?

@@ -55,4 +56,8 @@ ServerManager.prototype.createServer = function(options) {
return server;
}

ServerManager.prototype.toggleServerAuth = function(shouldUseAuth = false){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the name of the function is not right. IMO it should be setServerAuth.

@webplusai
Copy link
Contributor Author

I have implemented a flag that allows the app to toggle on authentication. By default, when the user starts the app using the npm run start command, it runs without requiring authentication. But when the app is started using the npm run start -- --mws-use-auth command then authentication is turned on.

Would you check and let me know if this is what you want @Jermolene ?

@Jermolene
Copy link
Member

I have implemented a flag that allows the app to toggle on authentication. By default, when the user starts the app using the npm run start command, it runs without requiring authentication. But when the app is started using the npm run start -- --mws-use-auth command then authentication is turned on.

Would you check and let me know if this is what you want @Jermolene ?

I don't think that is the right way to handle anonymous access. Users will need to be able to configure wikis independently, so that one may have anonymous read access, one may have both anonymous read and write access and another may be entirely access controlled.

I think that means that we can't have a server-wide switch that switches authentication on or off. We just need an access control system that allows a resource to be marked as permitting or blocking anonymous access.

@Jermolene
Copy link
Member

Hi @pmario while I don't think the concerns that you raised should block us from merging this PR, they are still relevant and I'd like to pick them up in a separate discussion thread here on GitHub. I am happy to copy across the relevant text from this thread, or perhaps it would make sense for you to initiate the discussion?

@pmario
Copy link
Member

pmario commented Oct 16, 2024

... I am happy to copy across the relevant text from this thread, or perhaps it would make sense for you to initiate the discussion?

I think security is a broader topic. So I will create a new discussion thread instead of an issue. So we can create new actionable issues from the discussion.

@webplusai
Copy link
Contributor Author

webplusai commented Oct 16, 2024

I have implemented a flag that allows the app to toggle on authentication. By default, when the user starts the app using the npm run start command, it runs without requiring authentication. But when the app is started using the npm run start -- --mws-use-auth command then authentication is turned on.
Would you check and let me know if this is what you want @Jermolene ?

I don't think that is the right way to handle anonymous access. Users will need to be able to configure wikis independently, so that one may have anonymous read access, one may have both anonymous read and write access and another may be entirely access controlled.

I think that means that we can't have a server-wide switch that switches authentication on or off. We just need an access control system that allows a resource to be marked as permitting or blocking anonymous access.

@Jermolene Do we need to keep track of which user owns/created which resource?
Also, there are some system resources, do we make these accessible to all users?

@Jermolene
Copy link
Member

@Jermolene Do we need to keep track of which user owns/created which resource? Also, there are some system resources, do we make these accessible to all users?

That would certainly be useful but it shouldn't block merging this PR.

Copy link
Member

@pmario pmario left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just some thoughts.

I think the API should be versioned. Which makes it much easier to change it in the future and also can make it backwards compatible to run more versions at the same time

@@ -641,7 +641,7 @@ NavigatorWidget.prototype.handleManageACLTiddlersEvent = function() {
var paths = pathname.split("/");
var recipeName = paths[paths.length - 1];
var bagName = document.querySelector("h1.tc-site-title").innerHTML;
window.location.href = "/admin/manage-acl/"+recipeName+"/"+bagName
window.location.href = "/admin/acl/"+recipeName+"/"+bagName
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the API paths should not be so specific. eg: /admin/ is very specific.

I would suggest /api/v1/acl/* as base path. Which would make it consistent and it implies "admin" so it can be skipped.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bear in mind that our objective with this PR is to find the shortest path to enable us to merge it. These considerations are something that we can come back to.


exports.method = "POST";

exports.path = /^\/admin\/delete-acl\/?$/;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: /api/v1/alc/<resource> -- I am not sure if the path needs to contain the action delete since it is defined by the HTML command DELETE -- IMO we only need to specify the resource that should be deleted.


exports.method = "GET";

exports.path = /^\/admin\/acl\/(.+)$/;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GET /api/v1/acl/ ... imo would be more consistent as it is now

@Jermolene
Copy link
Member

Jermolene commented Oct 23, 2024

(post deleted; I was inadvertently commenting on an earlier commit)

@Jermolene
Copy link
Member

Apologies @webplusai I've deleted my previous comment; I was inadvertently using a previous commit.

Copy link
Member

@Jermolene Jermolene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @webplusai there are some issues below that I would like to resolve, but I should first once again congratulate you on this PR. It is a huge piece of work and you've achieved a very high standard. But what I really appreciate is how much you've been able to learn of the inwardness of TiddlyWiki itself. The templates you've created are a great example.


var crypto = require("crypto");

function Authenticator($tw) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In TiddlyWiki, $tw is a global that is automatically available in every module. It should not be passed around as a parameter.

if(!(this instanceof Authenticator)) {
return new Authenticator($tw);
}
this.sqlTiddlerDatabase = $tw.mws.store.sqlTiddlerDatabase;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use a global reference to the database? I think it would be better passed as a parameter to the constructor.

4. Access Control List (ACL)

## Running the App
By default, the Multiwiki Server starts up without authentication enabled. In order to enabled authentication, start the app using the following command:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this command is needed. I would expect to enable authentication by applying access controls to a resource that requires authentication.

@@ -44,7 +44,8 @@ NavigatorWidget.prototype.render = function(parent,nextSibling) {
{type: "tm-fold-tiddler", handler: "handleFoldTiddlerEvent"},
{type: "tm-fold-other-tiddlers", handler: "handleFoldOtherTiddlersEvent"},
{type: "tm-fold-all-tiddlers", handler: "handleFoldAllTiddlersEvent"},
{type: "tm-unfold-all-tiddlers", handler: "handleUnfoldAllTiddlersEvent"}
{type: "tm-unfold-all-tiddlers", handler: "handleUnfoldAllTiddlersEvent"},
{type: "tm-manage-acl", handler: "handleManageACLTiddlersEvent"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The navigator widget is part of the TiddlyWiki core. It cannot include components that are specific to MWS.

In this case, rather than using a message handler, the most appropriate technique would be for the MWS client plugin to provide a global function that yields the URL of the appropriate admin page.

title: $:/plugins/tiddlywiki/multiwikiserver/templates/add-user-modal

\define add-user-actions()
<$action-sendmessage $message="tm-server-request"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may be missing something obvious, but where is the definition of the tm-server-request message handler?

"all-roles": JSON.stringify(allRoles),
"is-current-user-profile": state.authenticatedUser && state.authenticatedUser.user_id === user_id ? "yes" : "no",
"is-current-user-profile": state.authenticatedUser && state.authenticatedUser.user_id == user_id ? "yes" : "no",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually use === ... Is it not possible here?

</ul>
</div>
</div>
</div>

<!-- <$reveal type="match" state="is-current-user-profile" text="yes"> -->
<$list filter="[<user-is-admin>match[yes]] [<is-current-user-profile>match[yes]]">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO you should use the conditional shortcut here: https://tiddlywiki.com/#Conditional%20Shortcut%20Syntax

If the list-widget is used as an IF construction, we use the variable="ignore" or variable="null" because by default list-widget modifies the currentTiddler variable, which may not be desired. -- Just a thought

@@ -58,7 +56,7 @@ GET /admin/users/:user_id
"user": JSON.stringify(user),
"user-role": JSON.stringify(userRole),
"all-roles": JSON.stringify(allRoles),
"is-current-user-profile": state.authenticatedUser && state.authenticatedUser.user_id == user_id ? "yes" : "no",
"is-current-user-profile": state.authenticatedUser && state.authenticatedUser.user_id === parseInt(user_id) ? "yes" : "no",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseInt() needs a radix as a second parameter. So it should be parseInt(user_id, 10) otherwise there will be wired problems.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TW has a built-in utility function $tw.utils.parseInt() that wraps parseInt.

@Jermolene
Copy link
Member

Thank you @webplusai I think we are at a good place to merge this. There's a lot more to do to clean things up and improve the user experience, but I think it's going to be much easier to make progress after merging this.

Again I really want to congratulate you on your work here. TiddlyWiki is a somewhat non-standard environment and I'm delighted to see how you have been able to adapt to it and take advantage of its features.

@Jermolene Jermolene merged commit 6a7612d into TiddlyWiki:multi-wiki-support Oct 30, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants