diff --git a/addons/api/mirage/factories/account.js b/addons/api/mirage/factories/account.js index f5da7b5af..9ab7b259b 100644 --- a/addons/api/mirage/factories/account.js +++ b/addons/api/mirage/factories/account.js @@ -1,6 +1,7 @@ import factory from '../generated/factories/account'; import { random, internet } from 'faker'; import permissions from '../helpers/permissions'; +import generateId from '../helpers/id'; export default factory.extend({ authorized_actions: () => @@ -11,6 +12,9 @@ export default factory.extend({ 'delete', 'set-password', ], + + id: () => generateId('acct_'), + attributes() { switch (this.type) { case 'password': diff --git a/addons/api/mirage/factories/auth-method.js b/addons/api/mirage/factories/auth-method.js index 2196a13a3..f89e752e3 100644 --- a/addons/api/mirage/factories/auth-method.js +++ b/addons/api/mirage/factories/auth-method.js @@ -1,6 +1,7 @@ import factory from '../generated/factories/auth-method'; import { trait } from 'ember-cli-mirage'; import permissions from '../helpers/permissions'; +import generateId from '../helpers/id'; const types = ['password', 'oidc']; @@ -18,7 +19,8 @@ export default factory.extend({ 'managed-groups': ['create', 'list'], }; }, - id: (i) => `auth-method-id-${i}`, + + id: () => generateId('am_'), // Cycle through available types type: (i) => types[i % types.length], diff --git a/addons/api/mirage/factories/credential-library.js b/addons/api/mirage/factories/credential-library.js index 621ae6410..4aed98912 100644 --- a/addons/api/mirage/factories/credential-library.js +++ b/addons/api/mirage/factories/credential-library.js @@ -1,11 +1,12 @@ import factory from '../generated/factories/credential-library'; import { random, system } from 'faker'; import permissions from '../helpers/permissions'; +import generateId from '../helpers/id'; const types = ['vault']; export default factory.extend({ - id: (i) => `credential-library-id-${i}`, + id: () => generateId('cl_'), type: (i) => types[i % types.length], authorized_actions: () => diff --git a/addons/api/mirage/factories/credential-store.js b/addons/api/mirage/factories/credential-store.js index e84c494ca..0858d8e48 100644 --- a/addons/api/mirage/factories/credential-store.js +++ b/addons/api/mirage/factories/credential-store.js @@ -2,6 +2,7 @@ import factory from '../generated/factories/credential-store'; import { random, internet, datatype } from 'faker'; import { trait } from 'ember-cli-mirage'; import permissions from '../helpers/permissions'; +import generateId from '../helpers/id'; const types = ['vault']; @@ -18,7 +19,7 @@ export default factory.extend({ 'credential-libraries': ['create', 'list'], }; }, - id: (i) => `credential-store-id-${i}`, + id: () => generateId('cs_'), type: (i) => types[i % types.length], attributes() { diff --git a/addons/api/mirage/factories/group.js b/addons/api/mirage/factories/group.js index 6a16d3fb0..b3de1ac9c 100644 --- a/addons/api/mirage/factories/group.js +++ b/addons/api/mirage/factories/group.js @@ -1,6 +1,7 @@ import factory from '../generated/factories/group'; import { trait } from 'ember-cli-mirage'; import permissions from '../helpers/permissions'; +import generateId from '../helpers/id'; export default factory.extend({ authorized_actions: () => @@ -12,7 +13,8 @@ export default factory.extend({ 'add-members', 'remove-members', ], - id: (i) => `group-${i}`, + + id: () => generateId('g_'), /** * Generates some users for the same scope and assigns them to the group diff --git a/addons/api/mirage/factories/host-catalog.js b/addons/api/mirage/factories/host-catalog.js index 0cf046228..207c06d37 100644 --- a/addons/api/mirage/factories/host-catalog.js +++ b/addons/api/mirage/factories/host-catalog.js @@ -2,6 +2,7 @@ import factory from '../generated/factories/host-catalog'; import { trait } from 'ember-cli-mirage'; import permissions from '../helpers/permissions'; import { datatype, address, random } from 'faker'; +import generateId from '../helpers/id'; const types = ['static', 'plugin']; // Represents known plugin types, except "foobar" which models the possibility @@ -11,7 +12,7 @@ const pluginTypes = ['aws', 'azure', 'foobar']; let pluginTypeCounter = 1; export default factory.extend({ - id: (i) => `host-catalog-id-${i}`, + id: () => generateId('hc_'), // Cycle through available types type: (i) => types[i % types.length], diff --git a/addons/api/mirage/factories/host-set.js b/addons/api/mirage/factories/host-set.js index c417c067c..43b99e35b 100644 --- a/addons/api/mirage/factories/host-set.js +++ b/addons/api/mirage/factories/host-set.js @@ -1,9 +1,10 @@ import factory from '../generated/factories/host-set'; import permissions from '../helpers/permissions'; import { datatype, internet, database } from 'faker'; +import generateId from '../helpers/id'; export default factory.extend({ - id: (i) => `host-set-id-${i}`, + id: () => generateId('hs_'), type() { return this.hostCatalog?.type || factory.attrs.type; }, diff --git a/addons/api/mirage/factories/host.js b/addons/api/mirage/factories/host.js index 3bf07f11a..79bcad1e5 100644 --- a/addons/api/mirage/factories/host.js +++ b/addons/api/mirage/factories/host.js @@ -1,9 +1,11 @@ import factory from '../generated/factories/host'; import permissions from '../helpers/permissions'; import { internet, datatype } from 'faker'; +import generateId from '../helpers/id'; export default factory.extend({ - id: (i) => `host-id-${i}`, + id: () => generateId('h_'), + type() { return this.hostCatalog?.type || factory.attrs.type; }, diff --git a/addons/api/mirage/factories/managed-group.js b/addons/api/mirage/factories/managed-group.js index 9460f847f..b43b2b68d 100644 --- a/addons/api/mirage/factories/managed-group.js +++ b/addons/api/mirage/factories/managed-group.js @@ -1,11 +1,11 @@ import factory from '../generated/factories/managed-group'; import { random } from 'faker'; import permissions from '../helpers/permissions'; +import generateId from '../helpers/id'; const types = ['oidc']; export default factory.extend({ - id: (i) => `managed-groups-id-${i}`, type: (i) => types[i % types.length], authorized_actions: () => @@ -16,6 +16,8 @@ export default factory.extend({ 'delete', ], + id: () => generateId('mg_'), + attributes() { switch (this.type) { case 'oidc': diff --git a/addons/api/mirage/factories/role.js b/addons/api/mirage/factories/role.js index be13712b8..841558fde 100644 --- a/addons/api/mirage/factories/role.js +++ b/addons/api/mirage/factories/role.js @@ -1,6 +1,7 @@ import factory from '../generated/factories/role'; import { trait } from 'ember-cli-mirage'; import permissions from '../helpers/permissions'; +import generateId from '../helpers/id'; export default factory.extend({ authorized_actions: () => @@ -19,6 +20,8 @@ export default factory.extend({ 'id=*;type=host-catalog;actions=create,read', ], + id: () => generateId('r_'), + /** * Adds principals to the role. */ diff --git a/addons/api/mirage/factories/scope.js b/addons/api/mirage/factories/scope.js index b631c00e0..c70e6dbf1 100644 --- a/addons/api/mirage/factories/scope.js +++ b/addons/api/mirage/factories/scope.js @@ -1,6 +1,7 @@ import factory from '../generated/factories/scope'; import { trait } from 'ember-cli-mirage'; import permissions from '../helpers/permissions'; +import generateId from '../helpers/id'; export default factory.extend({ type: 'global', @@ -27,15 +28,7 @@ export default factory.extend({ }; }, - /** - * Generates realistic-ish IDs while still being deterministic. - */ - id(i) { - let id = 'tv6fv3yz8p'; - if (i % 3) id = 'xk1i4dk50v'; - if (i % 2) id = 's9n819zgko'; - return `s_${id}${i}`; - }, + id: () => generateId('s_'), withChildren: trait({ afterCreate(record, server) { diff --git a/addons/api/mirage/factories/session.js b/addons/api/mirage/factories/session.js index a581fa9e4..f73895473 100644 --- a/addons/api/mirage/factories/session.js +++ b/addons/api/mirage/factories/session.js @@ -1,13 +1,15 @@ import factory from '../generated/factories/session'; import { trait } from 'ember-cli-mirage'; import { random } from 'faker'; +import generateId from '../helpers/id'; const statusStrings = ['pending', 'active', 'canceling', 'terminated']; export const pickRandomStatusString = () => random.arrayElement(statusStrings); export default factory.extend({ - id: (i) => `session-id-${i}`, + id: () => generateId('ss_'), + status: pickRandomStatusString, /** diff --git a/addons/api/mirage/factories/target.js b/addons/api/mirage/factories/target.js index 3e3cb17df..64248f999 100644 --- a/addons/api/mirage/factories/target.js +++ b/addons/api/mirage/factories/target.js @@ -2,6 +2,7 @@ import factory from '../generated/factories/target'; import { trait } from 'ember-cli-mirage'; import { random, datatype } from 'faker'; import permissions from '../helpers/permissions'; +import generateId from '../helpers/id'; const randomBoolean = (chance = 0.5) => Math.random() < chance; const hostSetChance = 0.3; @@ -21,6 +22,8 @@ export default factory.extend({ 'remove-credential-sources', ], + id: () => generateId('t_'), + /** * -1 means "unlimited" and we want to generate these on occasion. */ diff --git a/addons/api/mirage/factories/user.js b/addons/api/mirage/factories/user.js index 837adba44..dd577dd72 100644 --- a/addons/api/mirage/factories/user.js +++ b/addons/api/mirage/factories/user.js @@ -1,5 +1,6 @@ import factory from '../generated/factories/user'; import permissions from '../helpers/permissions'; +import generateId from '../helpers/id'; export default factory.extend({ authorized_actions: () => @@ -11,5 +12,5 @@ export default factory.extend({ 'add-accounts', 'remove-accounts', ], - id: (i) => `user-${i}`, + id: () => generateId('u_'), }); diff --git a/addons/api/mirage/helpers/id.js b/addons/api/mirage/helpers/id.js new file mode 100644 index 000000000..b8ee469db --- /dev/null +++ b/addons/api/mirage/helpers/id.js @@ -0,0 +1,41 @@ +const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'; + +/** + * The Mulberry32 PRNG, JavaScript implementation. This is a seedable PRNG, + * which we need in order to deterministically generate IDs which are stable + * across reloads. Unfortunately, the built-in `Math.random` function + * is not seedable. + * + * Source: + * https://github.com/bryc/code/blob/master/jshash/PRNGs.md#mulberry32 + * + * @param {number} a + * @return {number} + */ +function mulberry32(a = 0) { + return function () { + a += 0x6d2b79f5 | 0; + var t = Math.imul(a ^ (a >>> 15), 1 | a); + t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + }; +} + +const random = mulberry32(); + +/** + * Generates a random ID string at least 10 characters long with the + * specified prefix. + * + * @param {string} prefix + * @return {string} + */ +export default function (prefix = '') { + let result = ''; + for (let i = 0; i < 10; i++) { + result = result.concat( + characters[Math.floor(random() * characters.length)] + ); + } + return prefix.concat(result); +}