@tstdl/base 0.93.178 → 0.93.180
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/response.js +4 -3
- package/api/server/gateway.js +9 -3
- package/audit/auditor.d.ts +1 -2
- package/audit/drizzle/{0000_lumpy_thunderball.sql → 0000_shallow_elektra.sql} +1 -1
- package/audit/drizzle/meta/0000_snapshot.json +2 -2
- package/audit/drizzle/meta/_journal.json +2 -2
- package/authentication/README.md +87 -42
- package/authentication/authentication.api.d.ts +392 -53
- package/authentication/authentication.api.js +133 -28
- package/authentication/client/api.client.d.ts +3 -3
- package/authentication/client/api.client.js +4 -4
- package/authentication/client/authentication.service.d.ts +93 -23
- package/authentication/client/authentication.service.js +113 -28
- package/authentication/client/http-client.middleware.d.ts +1 -1
- package/authentication/client/http-client.middleware.js +5 -4
- package/authentication/client/module.d.ts +1 -1
- package/authentication/client/module.js +2 -2
- package/authentication/errors/index.d.ts +1 -1
- package/authentication/errors/index.js +1 -1
- package/authentication/errors/password-requirements.error.d.ts +5 -0
- package/authentication/errors/{secret-requirements.error.js → password-requirements.error.js} +2 -2
- package/authentication/models/authentication-password.model.d.ts +8 -0
- package/authentication/models/{authentication-credentials.model.js → authentication-password.model.js} +11 -17
- package/authentication/models/authentication-session.model.d.ts +0 -2
- package/authentication/models/authentication-session.model.js +1 -7
- package/authentication/models/authentication-totp-recovery-code.model.d.ts +6 -0
- package/authentication/models/authentication-totp-recovery-code.model.js +34 -0
- package/authentication/models/authentication-totp.model.d.ts +19 -0
- package/authentication/models/authentication-totp.model.js +51 -0
- package/authentication/models/authentication-used-totp-token.model.d.ts +5 -0
- package/authentication/models/authentication-used-totp-token.model.js +32 -0
- package/authentication/models/index.d.ts +6 -3
- package/authentication/models/index.js +6 -3
- package/authentication/models/{init-secret-reset-data.model.d.ts → init-password-reset-data.model.d.ts} +3 -3
- package/authentication/models/{init-secret-reset-data.model.js → init-password-reset-data.model.js} +5 -5
- package/authentication/models/password-check-result.model.d.ts +3 -0
- package/authentication/models/{secret-check-result.model.js → password-check-result.model.js} +6 -6
- package/authentication/models/subject.model.d.ts +0 -6
- package/authentication/models/subject.model.js +0 -6
- package/authentication/models/token.model.d.ts +16 -2
- package/authentication/server/authentication-ancillary.service.d.ts +6 -6
- package/authentication/server/authentication-ancillary.service.js +1 -1
- package/authentication/server/authentication-password-requirements.validator.d.ts +55 -0
- package/authentication/server/{authentication-secret-requirements.validator.js → authentication-password-requirements.validator.js} +22 -22
- package/authentication/server/authentication.api-controller.d.ts +55 -27
- package/authentication/server/authentication.api-controller.js +214 -39
- package/authentication/server/authentication.audit.d.ts +42 -5
- package/authentication/server/authentication.service.d.ts +182 -93
- package/authentication/server/authentication.service.js +628 -206
- package/authentication/server/drizzle/{0000_soft_tag.sql → 0000_odd_echo.sql} +59 -13
- package/authentication/server/drizzle/meta/0000_snapshot.json +345 -32
- package/authentication/server/drizzle/meta/_journal.json +2 -2
- package/authentication/server/helper.d.ts +16 -16
- package/authentication/server/helper.js +33 -34
- package/authentication/server/index.d.ts +1 -1
- package/authentication/server/index.js +1 -1
- package/authentication/server/module.d.ts +2 -2
- package/authentication/server/module.js +4 -2
- package/authentication/server/schemas.d.ts +11 -7
- package/authentication/server/schemas.js +7 -3
- package/authentication/tests/authentication-password-requirements.validator.test.js +29 -0
- package/authentication/tests/authentication.api-controller.test.js +49 -15
- package/authentication/tests/authentication.client-error-handling.test.js +3 -2
- package/authentication/tests/authentication.client-middleware.test.js +5 -5
- package/authentication/tests/authentication.client-service-methods.test.js +28 -14
- package/authentication/tests/authentication.client-service-refresh.test.js +7 -6
- package/authentication/tests/authentication.client-service.test.js +10 -8
- package/authentication/tests/authentication.service.test.js +37 -29
- package/authentication/tests/authentication.test-ancillary-service.d.ts +1 -1
- package/authentication/tests/authentication.test-ancillary-service.js +1 -1
- package/authentication/tests/brute-force-protection.test.js +211 -0
- package/authentication/tests/helper.test.js +25 -21
- package/authentication/tests/password-requirements.error.test.js +14 -0
- package/authentication/tests/remember.api.test.js +22 -14
- package/authentication/tests/remember.service.test.js +23 -16
- package/authentication/tests/subject.service.test.js +2 -2
- package/authentication/tests/suspended-subject.test.d.ts +1 -0
- package/authentication/tests/suspended-subject.test.js +120 -0
- package/authentication/tests/totp.enrollment.test.d.ts +1 -0
- package/authentication/tests/totp.enrollment.test.js +123 -0
- package/authentication/tests/totp.login.test.d.ts +1 -0
- package/authentication/tests/totp.login.test.js +213 -0
- package/authentication/tests/totp.recovery-codes.test.d.ts +1 -0
- package/authentication/tests/totp.recovery-codes.test.js +97 -0
- package/authentication/tests/totp.status.test.d.ts +1 -0
- package/authentication/tests/totp.status.test.js +72 -0
- package/circuit-breaker/postgres/drizzle/{0000_cooing_korath.sql → 0000_same_captain_cross.sql} +1 -1
- package/circuit-breaker/postgres/drizzle/meta/0000_snapshot.json +2 -2
- package/circuit-breaker/postgres/drizzle/meta/_journal.json +2 -2
- package/cryptography/cryptography.d.ts +336 -0
- package/cryptography/cryptography.js +328 -0
- package/cryptography/index.d.ts +4 -0
- package/cryptography/index.js +4 -0
- package/{utils → cryptography}/jwt.d.ts +22 -4
- package/{utils → cryptography}/jwt.js +36 -18
- package/cryptography/module.d.ts +35 -0
- package/cryptography/module.js +148 -0
- package/cryptography/tests/cryptography.test.d.ts +1 -0
- package/cryptography/tests/cryptography.test.js +175 -0
- package/cryptography/tests/jwt.test.d.ts +1 -0
- package/cryptography/tests/jwt.test.js +54 -0
- package/cryptography/tests/modern.test.d.ts +1 -0
- package/cryptography/tests/modern.test.js +105 -0
- package/cryptography/tests/module.test.d.ts +1 -0
- package/cryptography/tests/module.test.js +100 -0
- package/cryptography/tests/totp.test.d.ts +1 -0
- package/cryptography/tests/totp.test.js +108 -0
- package/cryptography/totp.d.ts +96 -0
- package/cryptography/totp.js +123 -0
- package/document-management/server/drizzle/{0000_curious_nighthawk.sql → 0000_sharp_scream.sql} +21 -21
- package/document-management/server/drizzle/meta/0000_snapshot.json +22 -22
- package/document-management/server/drizzle/meta/_journal.json +2 -2
- package/document-management/server/services/document-file.service.js +1 -1
- package/errors/errors.localization.d.ts +2 -2
- package/errors/errors.localization.js +2 -2
- package/errors/index.d.ts +1 -0
- package/errors/index.js +1 -0
- package/errors/too-many-requests.error.d.ts +5 -0
- package/errors/too-many-requests.error.js +7 -0
- package/examples/api/authentication.js +5 -5
- package/examples/api/custom-authentication.js +4 -3
- package/file/server/mime-type.js +1 -1
- package/http/http-body.d.ts +1 -0
- package/http/http-body.js +3 -0
- package/image-service/imgproxy/imgproxy-image-service.d.ts +0 -1
- package/image-service/imgproxy/imgproxy-image-service.js +9 -27
- package/key-value-store/postgres/drizzle/{0000_shocking_slipstream.sql → 0000_moaning_calypso.sql} +1 -1
- package/key-value-store/postgres/drizzle/meta/0000_snapshot.json +2 -2
- package/key-value-store/postgres/drizzle/meta/_journal.json +2 -2
- package/lock/postgres/drizzle/{0000_busy_tattoo.sql → 0000_nappy_wraith.sql} +1 -1
- package/lock/postgres/drizzle/meta/0000_snapshot.json +2 -2
- package/lock/postgres/drizzle/meta/_journal.json +2 -2
- package/logger/formatters/json.js +1 -1
- package/logger/formatters/pretty-print.js +1 -1
- package/mail/drizzle/{0000_numerous_the_watchers.sql → 0000_cultured_quicksilver.sql} +2 -2
- package/mail/drizzle/meta/0000_snapshot.json +4 -4
- package/mail/drizzle/meta/_journal.json +2 -9
- package/notification/server/drizzle/{0000_wise_pyro.sql → 0000_new_tenebrous.sql} +6 -6
- package/notification/server/drizzle/meta/0000_snapshot.json +7 -7
- package/notification/server/drizzle/meta/_journal.json +2 -2
- package/notification/tests/notification-flow.test.js +1 -8
- package/notification/tests/notification-type.service.test.js +3 -3
- package/openid-connect/oidc.service.js +2 -3
- package/orm/data-types/common.js +1 -1
- package/orm/server/drizzle/schema-converter.js +9 -4
- package/orm/server/encryption.js +1 -1
- package/orm/server/module.d.ts +0 -1
- package/orm/server/module.js +0 -4
- package/orm/server/repository.d.ts +2 -1
- package/orm/server/repository.js +7 -10
- package/orm/tests/encryption.test.js +4 -6
- package/orm/tests/repository-extra-coverage.test.js +0 -2
- package/orm/tests/repository-regression.test.js +0 -3
- package/package.json +9 -8
- package/password/README.md +1 -1
- package/password/have-i-been-pwned.js +1 -1
- package/rate-limit/postgres/drizzle/{0000_watery_rage.sql → 0000_serious_sauron.sql} +1 -1
- package/rate-limit/postgres/drizzle/meta/0000_snapshot.json +2 -2
- package/rate-limit/postgres/drizzle/meta/_journal.json +2 -2
- package/rate-limit/postgres/postgres-rate-limiter.d.ts +1 -1
- package/rate-limit/postgres/postgres-rate-limiter.js +1 -1
- package/rate-limit/rate-limiter.d.ts +1 -1
- package/rpc/tests/rpc.integration.test.js +25 -31
- package/supports.d.ts +1 -0
- package/supports.js +1 -0
- package/task-queue/postgres/drizzle/{0000_faithful_daimon_hellstrom.sql → 0000_dark_ronan.sql} +5 -5
- package/task-queue/postgres/drizzle/meta/0000_snapshot.json +10 -10
- package/task-queue/postgres/drizzle/meta/_journal.json +2 -9
- package/task-queue/postgres/task-queue.js +2 -2
- package/task-queue/tests/coverage-enhancement.test.js +2 -2
- package/test/drizzle/{0000_natural_cannonball.sql → 0000_organic_gamora.sql} +2 -2
- package/test/drizzle/meta/0000_snapshot.json +3 -4
- package/test/drizzle/meta/_journal.json +2 -9
- package/testing/integration-setup.d.ts +7 -3
- package/testing/integration-setup.js +119 -96
- package/utils/alphabet.d.ts +1 -0
- package/utils/alphabet.js +1 -0
- package/utils/base32.d.ts +4 -0
- package/utils/base32.js +49 -0
- package/utils/base64.d.ts +0 -2
- package/utils/base64.js +6 -70
- package/utils/equals.d.ts +13 -3
- package/utils/equals.js +29 -9
- package/utils/index.d.ts +1 -2
- package/utils/index.js +1 -2
- package/utils/random.d.ts +1 -0
- package/utils/random.js +14 -8
- package/authentication/errors/secret-requirements.error.d.ts +0 -5
- package/authentication/models/authentication-credentials.model.d.ts +0 -10
- package/authentication/models/secret-check-result.model.d.ts +0 -3
- package/authentication/server/authentication-secret-requirements.validator.d.ts +0 -55
- package/authentication/tests/authentication-ancillary.service.test.js +0 -13
- package/authentication/tests/authentication-secret-requirements.validator.test.js +0 -29
- package/authentication/tests/secret-requirements.error.test.js +0 -14
- package/mail/drizzle/0001_married_tarantula.sql +0 -12
- package/mail/drizzle/meta/0001_snapshot.json +0 -69
- package/orm/server/tokens.d.ts +0 -1
- package/orm/server/tokens.js +0 -2
- package/task-queue/postgres/drizzle/0001_rapid_infant_terrible.sql +0 -16
- package/task-queue/postgres/drizzle/meta/0001_snapshot.json +0 -753
- package/test/drizzle/0001_closed_the_captain.sql +0 -2
- package/test/drizzle/meta/0001_snapshot.json +0 -117
- package/utils/cryptography.d.ts +0 -137
- package/utils/cryptography.js +0 -201
- /package/authentication/tests/{authentication-ancillary.service.test.d.ts → authentication-password-requirements.validator.test.d.ts} +0 -0
- /package/authentication/tests/{authentication-secret-requirements.validator.test.d.ts → brute-force-protection.test.d.ts} +0 -0
- /package/authentication/tests/{secret-requirements.error.test.d.ts → password-requirements.error.test.d.ts} +0 -0
|
@@ -59,6 +59,7 @@ import { AuthenticationApiClient } from '../authentication/client/api.client.js'
|
|
|
59
59
|
import { configureAuthenticationClient } from '../authentication/client/index.js';
|
|
60
60
|
import { AuthenticationApiController, configureAuthenticationServer } from '../authentication/server/index.js';
|
|
61
61
|
import { configurePostgresCircuitBreaker } from '../circuit-breaker/postgres/module.js';
|
|
62
|
+
import { configureSecrets } from '../cryptography/module.js';
|
|
62
63
|
import { configureDocumentManagement } from '../document-management/server/index.js';
|
|
63
64
|
import { configureUndiciHttpClientAdapter } from '../http/client/adapters/undici.adapter.js';
|
|
64
65
|
import { configureHttpClient } from '../http/client/index.js';
|
|
@@ -128,118 +129,140 @@ export async function setupIsolatedIntegrationTest(options = {}) {
|
|
|
128
129
|
database: configParser.string('DATABASE_NAME', 'tstdl'),
|
|
129
130
|
...options.dbConfig,
|
|
130
131
|
};
|
|
132
|
+
const schema = options.orm?.schema ?? 'test';
|
|
133
|
+
configureSecrets({ key: 'tstdl-unit-tests' });
|
|
131
134
|
// 4. Configure ORM
|
|
132
135
|
// We disable autoMigrate here because APPLICATION_INITIALIZER is not used in integration tests
|
|
133
136
|
// We manually run migrations via bootstrapOrm below
|
|
134
137
|
configureOrm({
|
|
135
|
-
repositoryConfig: { schema
|
|
138
|
+
repositoryConfig: { schema },
|
|
136
139
|
connection: dbConfig,
|
|
137
|
-
encryptionSecret: options.orm?.encryptionSecret,
|
|
138
140
|
injector,
|
|
139
141
|
});
|
|
140
142
|
// 5. Database Resolution
|
|
141
143
|
// We resolve the DB here to allow for immediate schema operations below
|
|
142
144
|
const database = injector.resolve(Database);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
for (const provider of options.providers ?? []) {
|
|
146
|
+
injector.register(provider.provide, provider, { multi: provider.multi });
|
|
147
|
+
}
|
|
148
|
+
// 7. Optional Modules
|
|
149
|
+
if (options.modules?.messageBus ?? options.modules?.taskQueue ?? options.modules?.authentication ?? options.modules?.notification) {
|
|
150
|
+
configureLocalMessageBus({ injector });
|
|
151
|
+
}
|
|
152
|
+
if (options.modules?.taskQueue) {
|
|
153
|
+
configurePostgresTaskQueue({ injector });
|
|
154
|
+
}
|
|
155
|
+
if (options.modules?.circuitBreaker ?? options.modules?.taskQueue) {
|
|
156
|
+
configurePostgresCircuitBreaker({ injector });
|
|
157
|
+
}
|
|
158
|
+
if (options.modules?.rateLimiter ?? options.modules?.taskQueue ?? options.modules?.authentication) {
|
|
159
|
+
configurePostgresRateLimiter({ injector });
|
|
160
|
+
}
|
|
161
|
+
if (options.modules?.keyValueStore ?? options.modules?.authentication) {
|
|
162
|
+
configurePostgresKeyValueStore({ injector });
|
|
163
|
+
}
|
|
164
|
+
if (options.modules?.lock ?? options.modules?.authentication) {
|
|
165
|
+
configurePostgresLock({ injector });
|
|
166
|
+
}
|
|
167
|
+
if (options.modules?.signals ?? options.modules?.authentication ?? options.modules?.notification) {
|
|
168
|
+
configureDefaultSignalsImplementation();
|
|
169
|
+
}
|
|
170
|
+
if (options.modules?.audit ?? options.modules?.authentication) {
|
|
171
|
+
configureAudit({ injector });
|
|
172
|
+
}
|
|
173
|
+
if (options.modules?.authentication) {
|
|
174
|
+
configureSecrets({ key: 'test-secret', injector });
|
|
175
|
+
const fastHashDeriveOptions = {
|
|
176
|
+
algorithm: {
|
|
177
|
+
name: 'Argon2id',
|
|
178
|
+
memory: 1024, // 1 MiB
|
|
179
|
+
parallelism: 1,
|
|
180
|
+
passes: 1,
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
const fastTotpHashingOptions = {
|
|
184
|
+
codeHashAlgorithm: 'SHA-1',
|
|
185
|
+
recoveryCodeHashOptions: {
|
|
186
|
+
algorithm: fastHashDeriveOptions.algorithm,
|
|
187
|
+
length: 64,
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
configureAuthenticationServer({
|
|
191
|
+
serviceOptions: {
|
|
192
|
+
passwordHashing: fastHashDeriveOptions,
|
|
193
|
+
totp: fastTotpHashingOptions,
|
|
194
|
+
...options.authentication?.options,
|
|
195
|
+
},
|
|
196
|
+
authenticationAncillaryService: options.authentication?.ancillaryService,
|
|
197
|
+
injector,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
if (options.modules?.notification) {
|
|
201
|
+
configureNotification({ injector });
|
|
202
|
+
}
|
|
203
|
+
if (options.modules?.documentManagement) {
|
|
204
|
+
configureDocumentManagement({
|
|
205
|
+
ancillaryService: undefined, // Should be overridden by test if needed
|
|
206
|
+
authorizationService: undefined, // Should be overridden by test if needed
|
|
207
|
+
fileObjectStorageModule: 'docs',
|
|
208
|
+
fileUploadObjectStorageModule: 'uploads',
|
|
209
|
+
filePreviewObjectStorageModule: 'previews',
|
|
210
|
+
skipAi: true,
|
|
211
|
+
injector,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
if (options.modules?.objectStorage) {
|
|
215
|
+
const bucketPerModule = options.s3?.bucketPerModule ?? configParser.boolean('S3_BUCKET_PER_MODULE', true);
|
|
216
|
+
configureS3ObjectStorage({
|
|
217
|
+
endpoint: options.s3?.endpoint ?? configParser.string('S3_ENDPOINT', 'http://127.0.0.1:19552'),
|
|
218
|
+
accessKey: options.s3?.accessKey ?? configParser.string('S3_ACCESS_KEY', 'tstdl-dev'),
|
|
219
|
+
secretKey: options.s3?.secretKey ?? configParser.string('S3_SECRET_KEY', 'tstdl-dev'),
|
|
220
|
+
bucket: bucketPerModule ? undefined : (options.s3?.bucket ?? configParser.string('S3_BUCKET', 'test-bucket')),
|
|
221
|
+
bucketPerModule,
|
|
222
|
+
region: options.s3?.region ?? configParser.string('S3_REGION', 'us-east-1'),
|
|
223
|
+
forcePathStyle: options.s3?.forcePathStyle ?? configParser.boolean('S3_FORCE_PATH_STYLE', true),
|
|
224
|
+
injector,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
if (options.modules?.api ?? options.modules?.authentication) {
|
|
228
|
+
configureNodeHttpServer({ trustedProxiesCount: 0, injector });
|
|
229
|
+
configureApiServer({ controllers: [AuthenticationApiController], injector });
|
|
230
|
+
configureUndiciHttpClientAdapter({ injector });
|
|
231
|
+
configureAuthenticationClient({
|
|
232
|
+
authenticationApiClient: AuthenticationApiClient,
|
|
233
|
+
registerMiddleware: true,
|
|
234
|
+
}, injector);
|
|
235
|
+
if (options.modules.webServer ?? options.modules.api ?? options.modules.authentication) {
|
|
236
|
+
const port = options.api?.port ?? 0;
|
|
237
|
+
configureWebServerModule({ port, injector });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
await runMigrationSafely(database, schema, async () => {
|
|
146
241
|
if (isDefined(options.orm?.schema)) {
|
|
147
242
|
await database.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(options.orm.schema)}`);
|
|
148
243
|
}
|
|
149
|
-
// 7. Optional Modules
|
|
150
|
-
if (options.modules?.messageBus ?? options.modules?.taskQueue ?? options.modules?.authentication ?? options.modules?.notification) {
|
|
151
|
-
configureLocalMessageBus({ injector });
|
|
152
|
-
}
|
|
153
|
-
if (options.modules?.taskQueue) {
|
|
154
|
-
configurePostgresTaskQueue({ injector });
|
|
155
|
-
}
|
|
156
|
-
if (options.modules?.circuitBreaker ?? options.modules?.taskQueue) {
|
|
157
|
-
configurePostgresCircuitBreaker({ injector });
|
|
158
|
-
}
|
|
159
|
-
if (options.modules?.rateLimiter ?? options.modules?.taskQueue) {
|
|
160
|
-
configurePostgresRateLimiter({ injector });
|
|
161
|
-
}
|
|
162
|
-
if (options.modules?.keyValueStore ?? options.modules?.authentication) {
|
|
163
|
-
configurePostgresKeyValueStore({ injector });
|
|
164
|
-
}
|
|
165
|
-
if (options.modules?.lock ?? options.modules?.authentication) {
|
|
166
|
-
configurePostgresLock({ injector });
|
|
167
|
-
}
|
|
168
|
-
if (options.modules?.signals ?? options.modules?.authentication ?? options.modules?.notification) {
|
|
169
|
-
configureDefaultSignalsImplementation();
|
|
170
|
-
}
|
|
171
|
-
if (options.modules?.audit ?? options.modules?.authentication) {
|
|
172
|
-
configureAudit({ injector });
|
|
173
|
-
}
|
|
174
|
-
if (options.modules?.authentication) {
|
|
175
|
-
configureAuthenticationServer({
|
|
176
|
-
serviceOptions: {
|
|
177
|
-
secret: 'test-secret',
|
|
178
|
-
hashIterations: 10,
|
|
179
|
-
signingSecretsDerivationIterations: 10,
|
|
180
|
-
},
|
|
181
|
-
authenticationAncillaryService: options.authenticationAncillaryService,
|
|
182
|
-
injector,
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
if (options.modules?.notification) {
|
|
186
|
-
configureNotification({ injector });
|
|
187
|
-
}
|
|
188
|
-
if (options.modules?.documentManagement) {
|
|
189
|
-
configureDocumentManagement({
|
|
190
|
-
ancillaryService: undefined, // Should be overridden by test if needed
|
|
191
|
-
authorizationService: undefined, // Should be overridden by test if needed
|
|
192
|
-
fileObjectStorageModule: 'docs',
|
|
193
|
-
fileUploadObjectStorageModule: 'uploads',
|
|
194
|
-
filePreviewObjectStorageModule: 'previews',
|
|
195
|
-
skipAi: true,
|
|
196
|
-
injector,
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
244
|
await runInInjectionContext(injector, bootstrapOrm);
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
if (options.modules?.api ?? options.modules?.authentication) {
|
|
214
|
-
configureNodeHttpServer({ trustedProxiesCount: 0, injector });
|
|
215
|
-
configureApiServer({ controllers: [AuthenticationApiController], injector });
|
|
216
|
-
configureUndiciHttpClientAdapter({ injector });
|
|
217
|
-
configureAuthenticationClient({
|
|
218
|
-
authenticationApiClient: AuthenticationApiClient,
|
|
219
|
-
registerMiddleware: true,
|
|
220
|
-
}, injector);
|
|
221
|
-
if (options.modules.webServer ?? options.modules.api ?? options.modules.authentication) {
|
|
222
|
-
const port = options.api?.port ?? 0;
|
|
223
|
-
configureWebServerModule({ port, injector });
|
|
224
|
-
const webServerModule = await injector.resolveAsync(WebServerModule);
|
|
225
|
-
const httpServer = await injector.resolveAsync(HttpServer);
|
|
226
|
-
void webServerModule.run();
|
|
227
|
-
// Wait for server to be listening
|
|
228
|
-
while (true) {
|
|
229
|
-
try {
|
|
230
|
-
if (isNotNull(httpServer.port)) {
|
|
231
|
-
break;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
catch {
|
|
235
|
-
// ignore
|
|
245
|
+
});
|
|
246
|
+
if (options.modules?.api ?? options.modules?.authentication) {
|
|
247
|
+
if (options.modules.webServer ?? options.modules.api ?? options.modules.authentication) {
|
|
248
|
+
const webServerModule = await injector.resolveAsync(WebServerModule);
|
|
249
|
+
const httpServer = await injector.resolveAsync(HttpServer);
|
|
250
|
+
void webServerModule.run();
|
|
251
|
+
// Wait for server to be listening
|
|
252
|
+
while (true) {
|
|
253
|
+
try {
|
|
254
|
+
if (isNotNull(httpServer.port)) {
|
|
255
|
+
break;
|
|
236
256
|
}
|
|
237
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
238
257
|
}
|
|
239
|
-
|
|
258
|
+
catch {
|
|
259
|
+
// ignore
|
|
260
|
+
}
|
|
261
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
240
262
|
}
|
|
263
|
+
configureHttpClient({ baseUrl: options.api?.baseUrl ?? `http://localhost:${httpServer.port}`, injector });
|
|
241
264
|
}
|
|
242
|
-
}
|
|
265
|
+
}
|
|
243
266
|
return { injector, database };
|
|
244
267
|
}
|
|
245
268
|
export const integrationTest = baseTest.extend({
|
|
@@ -358,8 +381,8 @@ export async function dropTables(database, schema, tables) {
|
|
|
358
381
|
/**
|
|
359
382
|
* Helper to run a migration safely with a database advisory lock to prevent race conditions.
|
|
360
383
|
*/
|
|
361
|
-
async function runMigrationSafely(database, migration) {
|
|
362
|
-
const lockName =
|
|
384
|
+
async function runMigrationSafely(database, schema, migration) {
|
|
385
|
+
const lockName = `tstdl:migration:${schema}`;
|
|
363
386
|
await runWithAdvisoryLock(database, lockName, migration);
|
|
364
387
|
}
|
|
365
388
|
async function runWithAdvisoryLock(database, lockName, fn) {
|
package/utils/alphabet.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare const Alphabet: {
|
|
|
8
8
|
readonly UpperCaseNumbers: "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
9
9
|
readonly LowerUpperCaseNumbers: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
10
10
|
readonly ZBase32: "ybndrfg8ejkmcpqxot1uwisza345h769";
|
|
11
|
+
readonly Base32: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
11
12
|
readonly LowerCaseHex: "0123456789abcdef";
|
|
12
13
|
readonly UpperCaseHex: "0123456789ABCDEF";
|
|
13
14
|
};
|
package/utils/alphabet.js
CHANGED
|
@@ -8,6 +8,7 @@ export const Alphabet = defineEnum('Alphabet', {
|
|
|
8
8
|
UpperCaseNumbers: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
|
|
9
9
|
LowerUpperCaseNumbers: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
|
|
10
10
|
ZBase32: 'ybndrfg8ejkmcpqxot1uwisza345h769',
|
|
11
|
+
Base32: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
|
|
11
12
|
LowerCaseHex: '0123456789abcdef',
|
|
12
13
|
UpperCaseHex: '0123456789ABCDEF',
|
|
13
14
|
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** biome-ignore-all lint/suspicious/noBitwiseOperators: ok */
|
|
2
|
+
import type { BinaryData } from '../types/index.js';
|
|
3
|
+
export declare function encodeBase32(buffer: BinaryData, padding?: boolean): string;
|
|
4
|
+
export declare function decodeBase32(input: string): Uint8Array<ArrayBuffer>;
|
package/utils/base32.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** biome-ignore-all lint/suspicious/noBitwiseOperators: ok */
|
|
2
|
+
import { Alphabet } from './alphabet.js';
|
|
3
|
+
import { toUint8Array } from './binary.js';
|
|
4
|
+
import { assertDefined } from './type-guards.js';
|
|
5
|
+
const alphabet = Alphabet.Base32;
|
|
6
|
+
const charValueMap = new Map(alphabet.split('').map((char, index) => [char, index]));
|
|
7
|
+
export function encodeBase32(buffer, padding = true) {
|
|
8
|
+
const byteView = toUint8Array(buffer);
|
|
9
|
+
let result = '';
|
|
10
|
+
let bits = 0;
|
|
11
|
+
let value = 0;
|
|
12
|
+
for (let i = 0; i < byteView.byteLength; i++) {
|
|
13
|
+
value = (value << 8) | byteView[i];
|
|
14
|
+
bits += 8;
|
|
15
|
+
while (bits >= 5) {
|
|
16
|
+
const quantum = (value >>> (bits - 5)) & 31;
|
|
17
|
+
result += alphabet[quantum];
|
|
18
|
+
bits -= 5;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (bits > 0) {
|
|
22
|
+
result += alphabet[(value << (5 - bits)) & 31];
|
|
23
|
+
}
|
|
24
|
+
if (padding) {
|
|
25
|
+
while (result.length % 8 !== 0) {
|
|
26
|
+
result += '=';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
export function decodeBase32(input) {
|
|
32
|
+
const cleanedInput = input.replace(/=/g, '').toUpperCase();
|
|
33
|
+
const bytes = new Uint8Array((cleanedInput.length * 5 / 8) | 0);
|
|
34
|
+
let bits = 0;
|
|
35
|
+
let value = 0;
|
|
36
|
+
let byteIndex = 0;
|
|
37
|
+
for (let i = 0; i < cleanedInput.length; i++) {
|
|
38
|
+
const char = cleanedInput[i];
|
|
39
|
+
const charValue = charValueMap.get(char);
|
|
40
|
+
assertDefined(charValue, `Invalid base32 character at index ${i}.`);
|
|
41
|
+
value = (value << 5) | charValue;
|
|
42
|
+
bits += 5;
|
|
43
|
+
if (bits >= 8) {
|
|
44
|
+
bytes[byteIndex++] = (value >>> (bits - 8)) & 255;
|
|
45
|
+
bits -= 8;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return bytes;
|
|
49
|
+
}
|
package/utils/base64.d.ts
CHANGED
|
@@ -12,5 +12,3 @@ export declare function encodeBase64Url(array: BinaryData, bytesOffset?: number,
|
|
|
12
12
|
export declare function decodeBase64Url(base64Url: string): Uint8Array<ArrayBuffer>;
|
|
13
13
|
export declare function base64ToBase64Url(input: string): string;
|
|
14
14
|
export declare function base64UrlToBase64(input: string): string;
|
|
15
|
-
export declare function utf8ArrayToString(bytes: Uint8Array): string;
|
|
16
|
-
export declare function stringToUtf8Array(string: string): Uint8Array<ArrayBuffer>;
|
package/utils/base64.js
CHANGED
|
@@ -44,14 +44,14 @@ export function decodeBase64Url(base64Url) {
|
|
|
44
44
|
}
|
|
45
45
|
export function base64ToBase64Url(input) {
|
|
46
46
|
return input
|
|
47
|
-
.replace(/=/
|
|
48
|
-
.replace(/\+/
|
|
49
|
-
.replace(/\//
|
|
47
|
+
.replace(/=/g, '')
|
|
48
|
+
.replace(/\+/g, '-')
|
|
49
|
+
.replace(/\//g, '_');
|
|
50
50
|
}
|
|
51
51
|
export function base64UrlToBase64(input) {
|
|
52
52
|
return input.padEnd(input.length + ((4 - (input.length % 4)) % 4), '=')
|
|
53
|
-
.replace(/-/
|
|
54
|
-
.replace(/_/
|
|
53
|
+
.replace(/-/g, '+')
|
|
54
|
+
.replace(/_/g, '/');
|
|
55
55
|
}
|
|
56
56
|
function encodeBase64Fallback(data) {
|
|
57
57
|
const bytes = toUint8Array(data);
|
|
@@ -69,7 +69,7 @@ function encodeBase64Fallback(data) {
|
|
|
69
69
|
return base64.substring(0, base64.length - 2 + nMod3) + (nMod3 == 2 ? '' : nMod3 == 1 ? '=' : '==');
|
|
70
70
|
}
|
|
71
71
|
function decodeBase64Fallback(base64, blockSize) {
|
|
72
|
-
const clearedBase64 = base64.replace(/[^A-Za-z0-9+/]/
|
|
72
|
+
const clearedBase64 = base64.replace(/[^A-Za-z0-9+/]/g, '');
|
|
73
73
|
const inputLength = clearedBase64.length;
|
|
74
74
|
const outputLength = isDefined(blockSize) ? Math.ceil(((inputLength * 3) + 1 >> 2) / blockSize) * blockSize : (inputLength * 3) + 1 >> 2;
|
|
75
75
|
const bytes = new Uint8Array(outputLength);
|
|
@@ -87,70 +87,6 @@ function decodeBase64Fallback(base64, blockSize) {
|
|
|
87
87
|
}
|
|
88
88
|
return bytes;
|
|
89
89
|
}
|
|
90
|
-
export function utf8ArrayToString(bytes) {
|
|
91
|
-
let string = '';
|
|
92
|
-
for (let index = 0; index < bytes.length; index++) {
|
|
93
|
-
const byte = bytes[index];
|
|
94
|
-
const charCode = byte > 251 && byte < 254 && index + 5 < bytes.length
|
|
95
|
-
? ((byte - 252) * 1073741824) + (bytes[++index] - 128 << 24) + (bytes[++index] - 128 << 18) + (bytes[++index] - 128 << 12) + (bytes[++index] - 128 << 6) + bytes[++index] - 128
|
|
96
|
-
: byte > 247 && byte < 252 && index + 4 < bytes.length
|
|
97
|
-
? (byte - 248 << 24) + (bytes[++index] - 128 << 18) + (bytes[++index] - 128 << 12) + (bytes[++index] - 128 << 6) + bytes[++index] - 128
|
|
98
|
-
: byte > 239 && byte < 248 && index + 3 < bytes.length
|
|
99
|
-
? (byte - 240 << 18) + (bytes[++index] - 128 << 12) + (bytes[++index] - 128 << 6) + bytes[++index] - 128
|
|
100
|
-
: byte > 223 && byte < 240 && index + 2 < bytes.length
|
|
101
|
-
? (byte - 224 << 12) + (bytes[++index] - 128 << 6) + bytes[++index] - 128
|
|
102
|
-
: byte > 191 && byte < 224 && index + 1 < bytes.length
|
|
103
|
-
? (byte - 192 << 6) + bytes[++index] - 128
|
|
104
|
-
: byte;
|
|
105
|
-
string += String.fromCharCode(charCode);
|
|
106
|
-
}
|
|
107
|
-
return string;
|
|
108
|
-
}
|
|
109
|
-
export function stringToUtf8Array(string) {
|
|
110
|
-
let bytesLength = 0;
|
|
111
|
-
for (let i = 0; i < string.length; i++) {
|
|
112
|
-
const char = string.charCodeAt(i);
|
|
113
|
-
bytesLength += char < 0x80 ? 1 : char < 0x800 ? 2 : char < 0x10000 ? 3 : char < 0x200000 ? 4 : char < 0x4000000 ? 5 : 6;
|
|
114
|
-
}
|
|
115
|
-
const bytes = new Uint8Array(bytesLength);
|
|
116
|
-
for (let byteIndex = 0, charIndex = 0; byteIndex < bytesLength; charIndex++) {
|
|
117
|
-
const char = string.charCodeAt(charIndex);
|
|
118
|
-
if (char < 128) {
|
|
119
|
-
bytes[byteIndex++] = char;
|
|
120
|
-
}
|
|
121
|
-
else if (char < 0x800) {
|
|
122
|
-
bytes[byteIndex++] = 192 + (char >>> 6);
|
|
123
|
-
bytes[byteIndex++] = 128 + (char & 63);
|
|
124
|
-
}
|
|
125
|
-
else if (char < 0x10000) {
|
|
126
|
-
bytes[byteIndex++] = 224 + (char >>> 12);
|
|
127
|
-
bytes[byteIndex++] = 128 + ((char >>> 6) & 63);
|
|
128
|
-
bytes[byteIndex++] = 128 + (char & 63);
|
|
129
|
-
}
|
|
130
|
-
else if (char < 0x200000) {
|
|
131
|
-
bytes[byteIndex++] = 240 + (char >>> 18);
|
|
132
|
-
bytes[byteIndex++] = 128 + ((char >>> 12) & 63);
|
|
133
|
-
bytes[byteIndex++] = 128 + ((char >>> 6) & 63);
|
|
134
|
-
bytes[byteIndex++] = 128 + (char & 63);
|
|
135
|
-
}
|
|
136
|
-
else if (char < 0x4000000) {
|
|
137
|
-
bytes[byteIndex++] = 248 + (char >>> 24);
|
|
138
|
-
bytes[byteIndex++] = 128 + ((char >>> 18) & 63);
|
|
139
|
-
bytes[byteIndex++] = 128 + ((char >>> 12) & 63);
|
|
140
|
-
bytes[byteIndex++] = 128 + ((char >>> 6) & 63);
|
|
141
|
-
bytes[byteIndex++] = 128 + (char & 63);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
bytes[byteIndex++] = 252 + (char >>> 30);
|
|
145
|
-
bytes[byteIndex++] = 128 + ((char >>> 24) & 63);
|
|
146
|
-
bytes[byteIndex++] = 128 + ((char >>> 18) & 63);
|
|
147
|
-
bytes[byteIndex++] = 128 + ((char >>> 12) & 63);
|
|
148
|
-
bytes[byteIndex++] = 128 + ((char >>> 6) & 63);
|
|
149
|
-
bytes[byteIndex++] = 128 + (char & 63);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return bytes;
|
|
153
|
-
}
|
|
154
90
|
function uint6ToBase64(nUint6) {
|
|
155
91
|
return nUint6 < 26
|
|
156
92
|
? nUint6 + 65
|
package/utils/equals.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** biome-ignore-all lint/suspicious/noBitwiseOperators: low level */
|
|
1
2
|
import type { BinaryData } from '../types/index.js';
|
|
2
3
|
import type { Comparator } from './sort.js';
|
|
3
4
|
export interface Equals<T = unknown> {
|
|
@@ -29,9 +30,18 @@ export declare function equals(a: any, b: any, options?: EqualsOptions, __intern
|
|
|
29
30
|
export declare function binaryEquals(bufferA: BinaryData, bufferB: BinaryData): boolean;
|
|
30
31
|
/**
|
|
31
32
|
* Compares two buffers in a way that is resistant to timing attacks.
|
|
32
|
-
*
|
|
33
|
-
* @param
|
|
33
|
+
* It short-circuits on length mismatch. So length is not a secret.
|
|
34
|
+
* @param a The first buffer to compare.
|
|
35
|
+
* @param b The second buffer to compare.
|
|
34
36
|
* @returns True if the buffers are equal, false otherwise.
|
|
35
37
|
*/
|
|
36
|
-
export declare function timingSafeBinaryEquals(
|
|
38
|
+
export declare function timingSafeBinaryEquals(a: BinaryData, b: BinaryData): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Compares two strings in a way that is resistant to timing attacks.
|
|
41
|
+
* It short-circuits on length mismatch. So length is not a secret.
|
|
42
|
+
* @param a The first string to compare. Its length is used to determine the iterations of the comparison.
|
|
43
|
+
* @param b The second string to compare. This should be the secret.
|
|
44
|
+
* @returns True if the strings are equal, false otherwise.
|
|
45
|
+
*/
|
|
46
|
+
export declare function timingSafeStringEquals(a: string, b: string): boolean;
|
|
37
47
|
export {};
|
package/utils/equals.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
/** biome-ignore-all lint/suspicious/noBitwiseOperators: low level */
|
|
1
2
|
import { toArray } from './array/array.js';
|
|
2
3
|
import { toUint8Array } from './binary.js';
|
|
3
4
|
import { compareByValue } from './comparison.js';
|
|
5
|
+
import { encodeUtf8 } from './encoding.js';
|
|
4
6
|
import { sort } from './iterable-helpers/sort.js';
|
|
5
7
|
import { objectKeys } from './object/object.js';
|
|
6
8
|
import { isArray, isDefined, isNotNull, isNull } from './type-guards.js';
|
|
@@ -116,17 +118,35 @@ export function binaryEquals(bufferA, bufferB) {
|
|
|
116
118
|
}
|
|
117
119
|
/**
|
|
118
120
|
* Compares two buffers in a way that is resistant to timing attacks.
|
|
119
|
-
*
|
|
120
|
-
* @param
|
|
121
|
+
* It short-circuits on length mismatch. So length is not a secret.
|
|
122
|
+
* @param a The first buffer to compare.
|
|
123
|
+
* @param b The second buffer to compare.
|
|
121
124
|
* @returns True if the buffers are equal, false otherwise.
|
|
122
125
|
*/
|
|
123
|
-
export function timingSafeBinaryEquals(
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
export function timingSafeBinaryEquals(a, b) {
|
|
127
|
+
const aArray = toUint8Array(a, false);
|
|
128
|
+
const bArray = toUint8Array(b, false);
|
|
129
|
+
if (aArray.length != bArray.length) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
let diff = 0;
|
|
133
|
+
for (let i = 0; i < aArray.length; i++) {
|
|
134
|
+
diff |= aArray[i] ^ bArray[i];
|
|
130
135
|
}
|
|
131
136
|
return diff == 0;
|
|
132
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Compares two strings in a way that is resistant to timing attacks.
|
|
140
|
+
* It short-circuits on length mismatch. So length is not a secret.
|
|
141
|
+
* @param a The first string to compare. Its length is used to determine the iterations of the comparison.
|
|
142
|
+
* @param b The second string to compare. This should be the secret.
|
|
143
|
+
* @returns True if the strings are equal, false otherwise.
|
|
144
|
+
*/
|
|
145
|
+
export function timingSafeStringEquals(a, b) {
|
|
146
|
+
if (a.length != b.length) {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
const aBytes = encodeUtf8(a);
|
|
150
|
+
const bBytes = encodeUtf8(b);
|
|
151
|
+
return timingSafeBinaryEquals(aBytes, bBytes);
|
|
152
|
+
}
|
package/utils/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './alphabet.js';
|
|
|
2
2
|
export * from './any-iterable-iterator.js';
|
|
3
3
|
export * from './async-iterator-iterable-iterator.js';
|
|
4
4
|
export * from './backoff.js';
|
|
5
|
+
export * from './base32.js';
|
|
5
6
|
export * from './base64.js';
|
|
6
7
|
export * from './benchmark.js';
|
|
7
8
|
export * from './binary-search.js';
|
|
@@ -11,7 +12,6 @@ export * from './comparison.js';
|
|
|
11
12
|
export * from './compression.js';
|
|
12
13
|
export * from './config-parser.js';
|
|
13
14
|
export * from './crc32.js';
|
|
14
|
-
export * from './cryptography.js';
|
|
15
15
|
export * from './date-time.js';
|
|
16
16
|
export * from './encoding.js';
|
|
17
17
|
export * from './enum.js';
|
|
@@ -23,7 +23,6 @@ export * from './format.js';
|
|
|
23
23
|
export * from './helpers.js';
|
|
24
24
|
export * from './html-link-utils.js';
|
|
25
25
|
export * from './image.js';
|
|
26
|
-
export * from './jwt.js';
|
|
27
26
|
export * from './map.js';
|
|
28
27
|
export * from './math.js';
|
|
29
28
|
export * from './merge.js';
|
package/utils/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export * from './alphabet.js';
|
|
|
2
2
|
export * from './any-iterable-iterator.js';
|
|
3
3
|
export * from './async-iterator-iterable-iterator.js';
|
|
4
4
|
export * from './backoff.js';
|
|
5
|
+
export * from './base32.js';
|
|
5
6
|
export * from './base64.js';
|
|
6
7
|
export * from './benchmark.js';
|
|
7
8
|
export * from './binary-search.js';
|
|
@@ -11,7 +12,6 @@ export * from './comparison.js';
|
|
|
11
12
|
export * from './compression.js';
|
|
12
13
|
export * from './config-parser.js';
|
|
13
14
|
export * from './crc32.js';
|
|
14
|
-
export * from './cryptography.js';
|
|
15
15
|
export * from './date-time.js';
|
|
16
16
|
export * from './encoding.js';
|
|
17
17
|
export * from './enum.js';
|
|
@@ -23,7 +23,6 @@ export * from './format.js';
|
|
|
23
23
|
export * from './helpers.js';
|
|
24
24
|
export * from './html-link-utils.js';
|
|
25
25
|
export * from './image.js';
|
|
26
|
-
export * from './jwt.js';
|
|
27
26
|
export * from './map.js';
|
|
28
27
|
export * from './math.js';
|
|
29
28
|
export * from './merge.js';
|
package/utils/random.d.ts
CHANGED
package/utils/random.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** biome-ignore-all lint/suspicious/noBitwiseOperators: low level */
|
|
1
2
|
import { Alphabet } from './alphabet.js';
|
|
2
3
|
const bufferSize = 20480;
|
|
3
4
|
const bufferBypassThreshold = (bufferSize / 2) + 1;
|
|
@@ -31,16 +32,21 @@ export function getRandomBytes(count, allowUnsafe = false) {
|
|
|
31
32
|
* @param alphabet alphabet to choose characters from. Defaults to {@link Alphabet.LowerUpperCaseNumbers}
|
|
32
33
|
*/
|
|
33
34
|
export function getRandomString(length, alphabet = Alphabet.LowerUpperCaseNumbers) {
|
|
34
|
-
let result = '';
|
|
35
35
|
if (length < 1) {
|
|
36
|
-
return
|
|
36
|
+
return '';
|
|
37
37
|
}
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
const alphabetLength = alphabet.length;
|
|
39
|
+
const mask = (2 << (31 - Math.clz32(alphabetLength - 1))) - 1;
|
|
40
|
+
const step = Math.ceil((1.6 * mask * length) / alphabetLength);
|
|
41
|
+
let result = '';
|
|
42
|
+
while (result.length < length) {
|
|
43
|
+
const bytes = getRandomBytes(step, true);
|
|
44
|
+
for (let i = 0; i < bytes.length && result.length < length; i++) {
|
|
45
|
+
const byte = bytes[i] & mask;
|
|
46
|
+
if (byte < alphabetLength) {
|
|
47
|
+
result += alphabet[byte];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
44
50
|
}
|
|
45
51
|
return result;
|
|
46
52
|
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { TenantEntity, type Uuid } from '../../orm/index.js';
|
|
2
|
-
export declare class AuthenticationCredentials extends TenantEntity {
|
|
3
|
-
subjectId: Uuid;
|
|
4
|
-
/** The version of the hash algorithm used. */
|
|
5
|
-
hashVersion: number;
|
|
6
|
-
/** The salt used to hash the secret. */
|
|
7
|
-
salt: Uint8Array<ArrayBuffer>;
|
|
8
|
-
/** The hashed secret. */
|
|
9
|
-
hash: Uint8Array<ArrayBuffer>;
|
|
10
|
-
}
|