I am trying to create a app with users and logins

I am new to uibakery and still learning how to build apps with it. I am coming from a different platform and having some issues porting over some functionality.

In my previous platform this app has a user can create an account with a password, and I would use dcodeIO (https://cdn.jsdelivr.net/gh/dcodeIO/bcrypt.js@3.0.2/index.js) JS library to encrypt the password before storing it in the database. I cannot figure out how to get this library to load.

In my custom code section I have

<script src="https://cdn.jsdelivr.net/gh/dcodeIO/bcrypt.js@3.0.2/index.js"></script>

Then I have tried to reference the functions a number of ways
dcodeIO.bcrypt.compareSync
bcrypt.compareSync
compareSync

but I am always getting an error similar to


**code step**has failed:


{

name: "ReferenceError",

message: "dcodeIO is not defined"

}

I am sure I am just not referencing the syntax correctly somehow, but I can’t seem to figure out what I am doing wrong.

Here is the JS code I am trying to run

const currentUser = await {{actions.PfindUserByEmail.trigger()}}

    console.log('checking variables passed',)
    console.log('username passed:', currentUser[0].User)
    console.log('password passed:', currentUser[0].Password)
    console.log('password in form:', {{ui.form.value.Password}})
    

    console.log('about to run is valid',)
		const isValid = dcodeIO.bcrypt.compareSync(password, storedpassword);

    console.log('finished running valid',)

    console.log('is Valid:', isValid)

The script stops execution when trying to invoke the dcodeIO library and everything prior is working as expected.

I am beyond frustrated and hoping someone can help me with some blatantly obvious misuse that I am doing in my implementation.

Please Kindly help!!

Thanks

Hi @coder911,

First of all, just so we are using the same terms, dcodeIO is the author of the library and the library’s name is bcrypt.


This is a pretty common issue, that will confuse many newer developers. What’s troubling you here, is the module system being used in that specific file of the library.

Module System?

You might know of the native module systems CommonJS, ESM/ECMAScript modules, etc. that let you import libraries.

Just as a quick refresh on those, here is a basic demonstration:

commonjs

// myScript.js
module.exports = function myFunction() {...};

// main.js
const myFunction = require('myScript.js');

ESM

// myScript.js
export default function myFunction() {...};

// main.js
import myFunction from 'myScript.js';

Some years ago, the author(s) of a library needed to provide multiple files, each for their respective module system, for example, library.amd.js, library.common.js, library.global.js, etc.

Nowadays, it’s enough to either provide files using ESM, which the many bundlers or some CDNs will automatically transpile to the needed format. Or, for the convenience of importing front-end libraries, provide a single file using UMD (Universal Module Definition), which is rather a pattern than a module system, that adapts to the environment it’s imported in.

The link of the bcrypt library you shared points to a file using ESM exports. But this isn’t supported by UIBakery, or actually the way they intend that external libraries are imported doesn’t support ESM. Well, at least if you just paste the <script> element with the src set.

Instead, what you want to import, is the UMD version of the library. I’ll just explain the general process I do when importing a library, so you can do it yourself for future imports:

  1. Look for the libary on any CDN, we’ll use jsdelivr. When you found it, at the top you will always see the code to “install” the library


    Generally, you want to use the import of the type Default. Most libraries use the UMD pattern in the default file. In this case, with bcrypt, you can even see /umd/ in the path of the file.

  2. Then add that code to your Custom Code section

  3. And bcrypt will be available in your actions

It’s easy, just like that!

Alternatively, if there is no link to a file that uses the UMD pattern or just attaches to the global object, you can use the ESM file. @Bradley_Graber showed in this response that you can just manually import the ESM module and attach it to the global object yourself like

<script type="module">
	import bcryptjs from 'https://cdn.jsdelivr.net/npm/bcryptjs@3.0.2/+esm';
	window.bcrypt = bcryptjs;
</script>
3 Likes

Thanks. That worked perfectly.

1 Like

Seems like bcrypt can not be used on server side action?

@simonzhang yep, that is how it’s supposed to be. If you “install” a library in the Custom Code tab, then it’s available to any script running on the client-side. But the Server Actions, as the name already says, are not executed on the client-side but on the server and the JavaScript runtime on the server has no clue what libraries you installed on the client-side. That’s because Server actions do not have access to the globalThis (window) object.

The docs about Server Actions also tries to explain the differences. The first sentence on that page says

Server actions enable you to create custom backend logic that runs entirely on the server, unlike regular actions that are executed in the browser. For better understanding, you can think of server actions as API endpoints.

and even displays further down the Difference between Client-side actions and Server actions and When to choose Client-side actions vs. Server actions

1 Like

Got it thanks, was exploring server side action for this. Initially I don’t want the hashing happen on the client side for security reason, I think I would make the hashing to a service that I can use, and do hashing and storing at the same time.

1 Like

@simonzhang just tested out some things, and it turns out you can use import in Server actions. So technically, you could do something like this

So you could use bcrypt in Server actions if you’d like to. But as you can see, you need to provide an CSPRNG (cryptographic pseudorandom number generator) because neither Web Crypto API nor Node.js crypto are available.

Here is the code of the image above so you can see for yourself : )

import bcrypt from 'https://cdn.jsdelivr.net/npm/bcryptjs@3.0.2/+esm';
import isaac from 'https://cdn.jsdelivr.net/npm/isaac@0.0.5/+esm';

bcrypt.setRandomFallback((len) => {
	const buf = new Uint8Array(len);

	return buf.map(() => Math.floor(isaac.random() * 256));
});

return bcrypt.hashSync("myPassword", 10)
1 Like

Fantastic, thanks! a method that I got from the UI Bakery team is to create a webhook based automation and connect libraries there and use http action to call it from the client side. Automation is running on server.

2 Likes