Problem/Motivation

It is sometimes necessary to create random/unique strings on the frontend. For example, if a placeholder DOMElement needs to be created and then replaced at a later time, a unique ID may be needed to identify the placeholder element.

Proposed resolution

Add a new randomString method to the Drupal object.

User interface changes

None.

API changes

A new method randomString will exist on the window.Drupal object.

Data model changes

None.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

gabesullice created an issue. See original summary.

gabesullice’s picture

FileSize
1.07 KB

First attempt. This is valid for IE 11 and above.

gabesullice’s picture

Clean up.

GrandmaGlassesRopeMan’s picture

Status: Active » Needs work
Issue tags: +JavaScript
  1. +++ b/core/misc/drupal.es6.js
    @@ -570,4 +570,23 @@ window.Drupal = { behaviors: {}, locale: {} };
    +  Drupal.randomString = function () {
    

    This can be an arrow.

  2. +++ b/core/misc/drupal.es6.js
    @@ -570,4 +570,23 @@ window.Drupal = { behaviors: {}, locale: {} };
    +    return btoa(buffer.reduce((hash, byte) => {
    +      return hash.concat(String.fromCharCode(byte));
    +    }, ``));
    

    This is just returning the result of hash.concat(), you can drop the curly braces. Something like, return btoa(buffer.reduce((hash, byte) => hash.concat(String.fromCharCode(byte)), ''));

  3. +++ b/core/misc/drupal.es6.js
    @@ -570,4 +570,23 @@ window.Drupal = { behaviors: {}, locale: {} };
    +    }, ``));
    

    Instead of ``, it can be '' since no replacements are happening.

gabesullice’s picture

FileSize
1.04 KB
1009 bytes

1. Did I do that right?

2. Forgot that JS code style has a longer length limit 👍

3. Since I know I need the concat method, it seems like I should just instantiate a String to begin with. https://stackoverflow.com/a/17256340.

gabesullice’s picture

FileSize
1.04 KB
500 bytes

Actually, let's just do it your way :P

dawehner’s picture

Before falling into similar pitfalls as we did in PHP I would suggest to either name this cryptographic safe or not. The implementation reads like this, but the usecase in the issue summary seems to not require that. Maybe it is enough to rename the method to cryptographicRandomString or so?

I'm curious, should we have something like drupal_html_id() like in PHP instead? This way at least its obvious what this function is build for.

GrandmaGlassesRopeMan’s picture

@dawehner I think it's probably a good idea to mark this as not cryptographically safe. That's not its intended use case, but it is much better than the horribly broken Math.random(). I think a name change on the method and some additional documentation would be nice.

gabesullice’s picture

Status: Needs work » Needs review
FileSize
1.29 KB
1.13 KB

@dawehner, the inspiration for this method came from drupal_html_id, but it indeed could be used for many more things than just HTML IDs.

While this appears to be cryptographic, I am in no way qualified to make that determination. I think it's best to explicitly say it is not for cryptographic purposes. That will give use more freedom to change this if necessary. If a cryptographically secure string generator is needed, lets do that elsewhere. It could be named something like secureRandomString(), for example. These docs could then be updated to point people to that method.

dawehner’s picture

Thank you for clarifying the indented usecase!

It is a bit weird though we say: The length might change at any moment.Wouldn't many usecases for a random string function return a fixed length? Random example for that: A test.

alexpott’s picture

+++ b/core/misc/drupal.es6.js
@@ -570,4 +570,26 @@ window.Drupal = { behaviors: {}, locale: {} };
+   * use where uniqueness is a requirement. For example, this method might be

I might be missing something but I can't see how uniqueness is guaranteed. The PHP equivalent had issues because we didn't guarantee this.

GrandmaGlassesRopeMan’s picture

@alexpott - I took a brief look into this. From the Mozilla docs,

The RandomSource.getRandomValues() method lets you get cryptographically strong random values. The array given as the parameter is filled with random numbers (random in its cryptographic meaning).

To guarantee enough performance, implementations are not using a truly random number generator, but they are using a pseudo-random number generator seeded with a value with enough entropy.

+++ b/core/misc/drupal.es6.js
@@ -570,4 +570,26 @@ window.Drupal = { behaviors: {}, locale: {} };
+   * will return a string that is guaranteed to be random that is suitable for

Perhaps we can just change this line to to something like, guaranteed to be pseudo-random, which is kind of strange.

@dawehner - We could just trim this string to a fixed length?

gabesullice’s picture

I might be missing something but I can't see how uniqueness is guaranteed. The PHP equivalent had issues because we didn't guarantee this.

@alexpott, the full docs say:

a string that is guaranteed to be random that is suitable for use where uniqueness is a requirement

I tried to be careful and say "guaranteed to be random" (which is as close to true as possible) and "suitable [for uniqueness]" because it doesn't attempt to store and compare previously generated values (for that, we could have just made a counter). I think 256 bits of cryptographically random material should be enough to avoid collisions though (I sure hope so!).

I can see how the wording might be a "little too clever by half" though. I'm open to suggestions :)

The length might change at any moment.Wouldn't many usecases for a random string function return a fixed length? Random example for that: A test

Hm. I guess I hadn't thought about using it that way. I was really trying to get people to rely on this for its purpose, not its implementation. I.e. use it in a test where you just need a random password or a unique ID. But if you're trying to generate a "paragraph" worth of random characters, you really shouldn't be using this function. In fact, it would be dangerous because you'll risk "using up" the entropy pool and then you'll start getting collisions.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

SteveChab’s picture

Issue tags: -JavaScript +JavaScript

We're doing this in our front-end JS. Not sure if it's helpful but thought I'd share.

function randomString(length = 6) {
  let result = "";
  const characters = `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`;
  const charactersLength = characters.length;
  for (let i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength));
  }
  return result;
}

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative

This issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.

Think this may need more discussion. From what I've learned on the php tests, when doing comparisions, is that we can't use random strings even if there is a 1 and million chance it could produce duplicates. So if the goal is to create a unique ID could it check if the random ID it generated exists already, if so generate another?

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.