AAE-30881 Remove jsrassign (#11863)

* [AAE-30881] - Remove jsrassign as dep

* [AAE-30881] - Remove jsrassign as dep

* [AAE-30881] - upgrade oidc package

* [AAE-30881] - added unit tests

* [AAE-30881] - fixing security issue

* [AAE-30881] - Fixed sonarcloud issue

* [AAE-30881] - Fixed sonarcloud issue
This commit is contained in:
Vito Albano
2026-05-07 10:37:29 +01:00
committed by GitHub
parent 57bf066164
commit 410490158f
8 changed files with 630 additions and 33 deletions
-1
View File
@@ -38,7 +38,6 @@
"allowedNonPeerDependencies": [
"cropperjs",
"angular-oauth2-oidc",
"angular-oauth2-oidc-jwks",
"date-fns",
"rxjs"
]
+1 -2
View File
@@ -18,8 +18,7 @@
},
"dependencies": {
"cropperjs": "^1.6.2",
"angular-oauth2-oidc": "17.0.2",
"angular-oauth2-oidc-jwks": "17.0.2",
"angular-oauth2-oidc": "19.0.0",
"date-fns": "^2.30.0",
"rxjs": "7.8.2"
},
+1
View File
@@ -21,3 +21,4 @@ export * from './oidc-auth.guard';
export * from './redirect-auth.service';
export * from './view/authentication-confirmation/authentication-confirmation.component';
export * from './oidc-authentication.service';
export * from './web-crypto-jwks-validation-handler';
@@ -28,7 +28,7 @@ import {
OAuthSuccessEvent,
OAuthLogger
} from 'angular-oauth2-oidc';
import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
import { WebCryptoJwksValidationHandler } from './web-crypto-jwks-validation-handler';
import { from, Observable, race, ReplaySubject } from 'rxjs';
import { distinctUntilChanged, filter, map, shareReplay, switchMap, take } from 'rxjs/operators';
import { AuthService } from './auth.service';
@@ -338,7 +338,7 @@ export class RedirectAuthService extends AuthService {
private configureAuth(config: AuthConfig): Promise<boolean> {
this.oauthService.configure(config);
this.oauthService.tokenValidationHandler = new JwksValidationHandler();
this.oauthService.tokenValidationHandler = new WebCryptoJwksValidationHandler();
if (config.sessionChecksEnabled) {
this.oauthService.events.pipe(filter((event) => event.type === 'session_terminated')).subscribe(() => {
@@ -0,0 +1,417 @@
/*!
* @license
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ValidationParams } from 'angular-oauth2-oidc';
import { WebCryptoJwksValidationHandler } from './web-crypto-jwks-validation-handler';
/**
* Encodes data to base64url format
*
* @param data - input data as ArrayBuffer or string
* @returns base64url encoded string
*/
function base64UrlEncode(data: ArrayBuffer | string): string {
const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data);
let binary = '';
for (const byte of bytes) {
binary += String.fromCharCode(byte);
}
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}
interface JwksKey extends JsonWebKey {
kid?: string;
use?: string;
}
interface TestKeyPair {
privateKey: CryptoKey;
publicJwk: JwksKey;
}
/**
* Generates an RSA key pair for testing
*
* @param kid - optional key ID to assign
* @returns test key pair with private key and public JWK
*/
async function generateRsaKeyPair(kid?: string): Promise<TestKeyPair> {
const keyPair = await crypto.subtle.generateKey(
{ name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: 'SHA-256' },
true,
['sign', 'verify']
);
const publicJwk: JwksKey = await crypto.subtle.exportKey('jwk', keyPair.publicKey);
publicJwk.use = 'sig';
if (kid) {
publicJwk.kid = kid;
}
return { privateKey: keyPair.privateKey, publicJwk };
}
/**
* Generates an EC key pair for testing
*
* @param namedCurve - elliptic curve name (e.g. P-256)
* @param kid - optional key ID to assign
* @returns test key pair with private key and public JWK
*/
async function generateEcKeyPair(namedCurve: string, kid?: string): Promise<TestKeyPair> {
const keyPair = await crypto.subtle.generateKey({ name: 'ECDSA', namedCurve }, true, ['sign', 'verify']);
const publicJwk: JwksKey = await crypto.subtle.exportKey('jwk', keyPair.publicKey);
publicJwk.use = 'sig';
if (kid) {
publicJwk.kid = kid;
}
return { privateKey: keyPair.privateKey, publicJwk };
}
/**
* Creates a signed JWT for testing
*
* @param header - JWT header object
* @param payload - JWT payload object
* @param privateKey - key to sign with
* @param algorithm - signing algorithm parameters
* @returns signed JWT string
*/
async function createSignedJwt(
header: object,
payload: object,
privateKey: CryptoKey,
algorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams
): Promise<string> {
const headerB64 = base64UrlEncode(JSON.stringify(header));
const payloadB64 = base64UrlEncode(JSON.stringify(payload));
const signingInput = new TextEncoder().encode(`${headerB64}.${payloadB64}`);
const signature = await crypto.subtle.sign(algorithm, privateKey, signingInput);
const signatureB64 = base64UrlEncode(signature);
return `${headerB64}.${payloadB64}.${signatureB64}`;
}
/**
* Builds a ValidationParams object with defaults for testing
*
* @param overrides - partial params to override defaults
* @returns complete ValidationParams
*/
function buildValidationParams(overrides: Partial<ValidationParams>): ValidationParams {
return {
idToken: '',
accessToken: '',
idTokenHeader: {},
idTokenClaims: {},
jwks: {},
loadKeys: undefined,
...overrides
} as ValidationParams;
}
describe('WebCryptoJwksValidationHandler', () => {
let handler: WebCryptoJwksValidationHandler;
beforeEach(() => {
handler = new WebCryptoJwksValidationHandler();
});
describe('parameter validation', () => {
it('should reject when idToken is missing', async () => {
const params = buildValidationParams({ idToken: '' });
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError('Parameter idToken expected!');
});
it('should reject when token has less than 3 parts', async () => {
const params = buildValidationParams({ idToken: 'part1.part2' });
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError(
'Invalid JWT format: token must have exactly 3 non-empty parts separated by dots.'
);
});
it('should reject when token has more than 3 parts', async () => {
const params = buildValidationParams({ idToken: 'a.b.c.d' });
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError(
'Invalid JWT format: token must have exactly 3 non-empty parts separated by dots.'
);
});
it('should reject when token has empty parts', async () => {
const params = buildValidationParams({ idToken: 'a..c' });
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError(
'Invalid JWT format: token must have exactly 3 non-empty parts separated by dots.'
);
});
it('should reject when idTokenHeader is missing', async () => {
const params = buildValidationParams({ idToken: 'a.b.c', idTokenHeader: null });
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError('Parameter idTokenHeader expected.');
});
it('should reject when jwks is missing', async () => {
const params = buildValidationParams({ idToken: 'a.b.c', idTokenHeader: { alg: 'RS256' }, jwks: null });
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError('Parameter jwks expected!');
});
it('should reject when jwks keys array is empty', async () => {
const params = buildValidationParams({ idToken: 'a.b.c', idTokenHeader: { alg: 'RS256' }, jwks: { keys: [] } });
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError('Array keys in jwks missing!');
});
it('should reject when algorithm is not supported', async () => {
const { publicJwk } = await generateRsaKeyPair('test-kid');
const params = buildValidationParams({
idToken: 'a.b.c',
idTokenHeader: { alg: 'none', kid: 'test-kid' },
jwks: { keys: [publicJwk] }
});
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError('Algorithm not supported: none');
});
it('should reject when algorithm is missing and no kid is present', async () => {
const { publicJwk } = await generateRsaKeyPair();
const params = buildValidationParams({
idToken: 'a.b.c',
idTokenHeader: {},
jwks: { keys: [publicJwk] }
});
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError('Algorithm not supported: <none>');
});
it('should reject when algorithm is unsupported and no kid is present', async () => {
const { publicJwk } = await generateRsaKeyPair();
const params = buildValidationParams({
idToken: 'a.b.c',
idTokenHeader: { alg: 'HS256' },
jwks: { keys: [publicJwk] }
});
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError('Algorithm not supported: HS256');
});
});
describe('key selection by kid', () => {
it('should select the key matching the kid in the token header', async () => {
const key1 = await generateRsaKeyPair('key-1');
const key2 = await generateRsaKeyPair('key-2');
const header = { alg: 'RS256', kid: 'key-2' };
const payload = { sub: '123' };
const idToken = await createSignedJwt(header, payload, key2.privateKey, { name: 'RSASSA-PKCS1-v1_5' });
const params = buildValidationParams({
idToken,
idTokenHeader: header,
jwks: { keys: [key1.publicJwk, key2.publicJwk] }
});
await expectAsync(handler.validateSignature(params)).toBeResolved();
});
it('should reject when kid does not match any key after retry', async () => {
const key1 = await generateRsaKeyPair('key-1');
const params = buildValidationParams({
idToken: 'a.b.c',
idTokenHeader: { alg: 'RS256', kid: 'unknown-kid' },
jwks: { keys: [key1.publicJwk] },
loadKeys: () => Promise.resolve({ keys: [key1.publicJwk] })
});
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError(/expected key not found in property jwks/);
});
});
describe('key selection without kid', () => {
it('should select the single matching key by kty and use', async () => {
const rsaKey = await generateRsaKeyPair();
const header = { alg: 'RS256' };
const payload = { sub: '456' };
const idToken = await createSignedJwt(header, payload, rsaKey.privateKey, { name: 'RSASSA-PKCS1-v1_5' });
const params = buildValidationParams({
idToken,
idTokenHeader: header,
jwks: { keys: [rsaKey.publicJwk] }
});
await expectAsync(handler.validateSignature(params)).toBeResolved();
});
it('should reject when multiple keys match without kid', async () => {
const key1 = await generateRsaKeyPair();
const key2 = await generateRsaKeyPair();
const params = buildValidationParams({
idToken: 'a.b.c',
idTokenHeader: { alg: 'RS256' },
jwks: { keys: [key1.publicJwk, key2.publicJwk] }
});
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError(
'More than one matching key found. Please specify a kid in the id_token header.'
);
});
it('should reject when no key matches after retry', async () => {
const ecKey = await generateEcKeyPair('P-256');
const params = buildValidationParams({
idToken: 'a.b.c',
idTokenHeader: { alg: 'RS256' },
jwks: { keys: [ecKey.publicJwk] },
loadKeys: () => Promise.resolve({ keys: [ecKey.publicJwk] })
});
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError('No matching key found.');
});
});
describe('loadKeys retry', () => {
it('should call loadKeys and retry when key is not found on first attempt', async () => {
const rsaKey = await generateRsaKeyPair('delayed-key');
const header = { alg: 'RS256', kid: 'delayed-key' };
const payload = { sub: '789' };
const idToken = await createSignedJwt(header, payload, rsaKey.privateKey, { name: 'RSASSA-PKCS1-v1_5' });
const otherKey = await generateRsaKeyPair('other-key');
const emptyJwks = { keys: [otherKey.publicJwk] };
const loadedJwks = { keys: [rsaKey.publicJwk] };
const loadKeysSpy = jasmine.createSpy('loadKeys').and.returnValue(Promise.resolve(loadedJwks));
const params = buildValidationParams({
idToken,
idTokenHeader: header,
jwks: emptyJwks,
loadKeys: loadKeysSpy
});
await expectAsync(handler.validateSignature(params)).toBeResolved();
expect(loadKeysSpy).toHaveBeenCalledTimes(1);
});
});
describe('RS256 signature verification', () => {
it('should resolve for a valid RS256 signature', async () => {
const rsaKey = await generateRsaKeyPair('rsa-kid');
const header = { alg: 'RS256', kid: 'rsa-kid' };
const payload = { sub: 'user1', iat: Math.floor(Date.now() / 1000) };
const idToken = await createSignedJwt(header, payload, rsaKey.privateKey, { name: 'RSASSA-PKCS1-v1_5' });
const params = buildValidationParams({
idToken,
idTokenHeader: header,
jwks: { keys: [rsaKey.publicJwk] }
});
await expectAsync(handler.validateSignature(params)).toBeResolved();
});
it('should reject for a tampered RS256 token', async () => {
const rsaKey = await generateRsaKeyPair('rsa-kid');
const header = { alg: 'RS256', kid: 'rsa-kid' };
const payload = { sub: 'user1' };
const idToken = await createSignedJwt(header, payload, rsaKey.privateKey, { name: 'RSASSA-PKCS1-v1_5' });
const parts = idToken.split('.');
const tamperedPayload = base64UrlEncode(JSON.stringify({ sub: 'attacker' }));
const tamperedToken = `${parts[0]}.${tamperedPayload}.${parts[2]}`;
const params = buildValidationParams({
idToken: tamperedToken,
idTokenHeader: header,
jwks: { keys: [rsaKey.publicJwk] }
});
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError('Signature not valid');
});
it('should reject when signed with a different key', async () => {
const signingKey = await generateRsaKeyPair('signing-key');
const verifyKey = await generateRsaKeyPair('verify-key');
const header = { alg: 'RS256', kid: 'verify-key' };
const payload = { sub: 'user1' };
const idToken = await createSignedJwt(header, payload, signingKey.privateKey, { name: 'RSASSA-PKCS1-v1_5' });
const params = buildValidationParams({
idToken,
idTokenHeader: header,
jwks: { keys: [verifyKey.publicJwk] }
});
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError('Signature not valid');
});
});
describe('ES256 signature verification', () => {
it('should resolve for a valid ES256 signature', async () => {
const ecKey = await generateEcKeyPair('P-256', 'ec-kid');
const header = { alg: 'ES256', kid: 'ec-kid' };
const payload = { sub: 'user2' };
const idToken = await createSignedJwt(header, payload, ecKey.privateKey, { name: 'ECDSA', hash: 'SHA-256' });
const params = buildValidationParams({
idToken,
idTokenHeader: header,
jwks: { keys: [ecKey.publicJwk] }
});
await expectAsync(handler.validateSignature(params)).toBeResolved();
});
it('should reject for a tampered ES256 token', async () => {
const ecKey = await generateEcKeyPair('P-256', 'ec-kid');
const header = { alg: 'ES256', kid: 'ec-kid' };
const payload = { sub: 'user2' };
const idToken = await createSignedJwt(header, payload, ecKey.privateKey, { name: 'ECDSA', hash: 'SHA-256' });
const parts = idToken.split('.');
const tamperedPayload = base64UrlEncode(JSON.stringify({ sub: 'attacker' }));
const tamperedToken = `${parts[0]}.${tamperedPayload}.${parts[2]}`;
const params = buildValidationParams({
idToken: tamperedToken,
idTokenHeader: header,
jwks: { keys: [ecKey.publicJwk] }
});
await expectAsync(handler.validateSignature(params)).toBeRejectedWithError('Signature not valid');
});
});
describe('PS256 signature verification', () => {
it('should resolve for a valid PS256 signature', async () => {
const keyPair = await crypto.subtle.generateKey(
{ name: 'RSA-PSS', modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: 'SHA-256' },
true,
['sign', 'verify']
);
const publicJwk: JwksKey = await crypto.subtle.exportKey('jwk', keyPair.publicKey);
publicJwk.use = 'sig';
publicJwk.kid = 'ps-kid';
const header = { alg: 'PS256', kid: 'ps-kid' };
const payload = { sub: 'user3' };
const idToken = await createSignedJwt(header, payload, keyPair.privateKey, { name: 'RSA-PSS', saltLength: 32 });
const params = buildValidationParams({
idToken,
idTokenHeader: header,
jwks: { keys: [publicJwk] }
});
await expectAsync(handler.validateSignature(params)).toBeResolved();
});
});
});
@@ -0,0 +1,202 @@
/*!
* @license
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AbstractValidationHandler, ValidationParams } from 'angular-oauth2-oidc';
interface JwksKey extends JsonWebKey {
kid?: string;
use?: string;
}
export class WebCryptoJwksValidationHandler extends AbstractValidationHandler {
allowedAlgorithms: string[] = ['RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'PS256', 'PS384', 'PS512'];
gracePeriodInSec = 600;
async validateSignature(params: ValidationParams, retry = false): Promise<any> {
this.validateParams(params);
const keyId: string = params.idTokenHeader['kid'];
const jwksKeys: JwksKey[] = params.jwks['keys'];
const algorithm: string = params.idTokenHeader['alg'];
if (!algorithm || !this.allowedAlgorithms.includes(algorithm)) {
throw new Error('Algorithm not supported: ' + (algorithm || '<none>'));
}
const matchedKey = this.findMatchingKey(jwksKeys, keyId, algorithm);
if (!matchedKey && !retry && params.loadKeys) {
params.jwks = await params.loadKeys();
return this.validateSignature(params, true);
}
if (!matchedKey && retry) {
throw this.buildKeyNotFoundError(keyId);
}
const cryptoKey = await this.importKey(matchedKey, algorithm);
const isValid = await this.verifySignature(params.idToken, cryptoKey, algorithm);
if (!isValid) {
throw new Error('Signature not valid');
}
}
private validateParams(params: ValidationParams): void {
if (!params.idToken) {
throw new Error('Parameter idToken expected!');
}
const tokenParts = params.idToken.split('.');
if (tokenParts.length !== 3 || tokenParts.some((part) => !part)) {
throw new Error('Invalid JWT format: token must have exactly 3 non-empty parts separated by dots.');
}
if (!params.idTokenHeader) {
throw new Error('Parameter idTokenHeader expected.');
}
if (!params.jwks) {
throw new Error('Parameter jwks expected!');
}
if (!params.jwks['keys'] || !Array.isArray(params.jwks['keys']) || params.jwks['keys'].length === 0) {
throw new Error('Array keys in jwks missing!');
}
}
private findMatchingKey(jwksKeys: JwksKey[], keyId: string, algorithm: string): JwksKey | undefined {
if (keyId) {
return jwksKeys.find((jwk) => jwk.kid === keyId);
}
const keyType = this.algorithmToKeyType(algorithm);
const matchingKeys = jwksKeys.filter((jwk) => jwk.kty === keyType && jwk.use === 'sig');
if (matchingKeys.length > 1) {
throw new Error('More than one matching key found. Please specify a kid in the id_token header.');
}
return matchingKeys[0];
}
private buildKeyNotFoundError(keyId: string): Error {
if (!keyId) {
return new Error('No matching key found.');
}
return new Error(
'expected key not found in property jwks. ' +
'This property is most likely loaded with the ' +
'discovery document. ' +
'Expected key id (kid): ' +
keyId
);
}
private async importKey(jsonWebKey: JwksKey, algorithmName: string): Promise<CryptoKey> {
const importAlgorithm = this.getImportAlgorithm(algorithmName);
return crypto.subtle.importKey('jwk', jsonWebKey, importAlgorithm, false, ['verify']);
}
private async verifySignature(idToken: string, cryptoKey: CryptoKey, algorithmName: string): Promise<boolean> {
const tokenParts = idToken.split('.');
const headerAndPayload = new TextEncoder().encode(tokenParts[0] + '.' + tokenParts[1]);
const signature = this.base64UrlDecode(tokenParts[2]);
const verifyAlgorithm = this.getVerifyAlgorithm(algorithmName);
return crypto.subtle.verify(verifyAlgorithm, cryptoKey, signature, headerAndPayload);
}
private getImportAlgorithm(algorithmName: string): RsaHashedImportParams | EcKeyImportParams {
switch (algorithmName) {
case 'RS256':
return { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' };
case 'RS384':
return { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-384' };
case 'RS512':
return { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-512' };
case 'ES256':
return { name: 'ECDSA', namedCurve: 'P-256' };
case 'ES384':
return { name: 'ECDSA', namedCurve: 'P-384' };
case 'PS256':
return { name: 'RSA-PSS', hash: 'SHA-256' };
case 'PS384':
return { name: 'RSA-PSS', hash: 'SHA-384' };
case 'PS512':
return { name: 'RSA-PSS', hash: 'SHA-512' };
default:
throw new Error('Unsupported algorithm: ' + algorithmName);
}
}
private getVerifyAlgorithm(algorithmName: string): AlgorithmIdentifier | RsaPssParams | EcdsaParams {
switch (algorithmName) {
case 'RS256':
case 'RS384':
case 'RS512':
return { name: 'RSASSA-PKCS1-v1_5' };
case 'ES256':
return { name: 'ECDSA', hash: 'SHA-256' };
case 'ES384':
return { name: 'ECDSA', hash: 'SHA-384' };
case 'PS256':
return { name: 'RSA-PSS', saltLength: 32 };
case 'PS384':
return { name: 'RSA-PSS', saltLength: 48 };
case 'PS512':
return { name: 'RSA-PSS', saltLength: 64 };
default:
throw new Error('Unsupported algorithm: ' + algorithmName);
}
}
private base64UrlDecode(input: string): ArrayBuffer {
let base64 = input.replace(/-/g, '+').replace(/_/g, '/');
while (base64.length % 4 !== 0) {
base64 += '=';
}
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let index = 0; index < binary.length; index++) {
bytes[index] = binary.charCodeAt(index);
}
return bytes.buffer;
}
protected async calcHash(valueToHash: string, algorithm: string): Promise<string> {
const msgBuffer = new TextEncoder().encode(valueToHash);
const hashBuffer = await crypto.subtle.digest(algorithm, msgBuffer);
const hashArray = new Uint8Array(hashBuffer);
let result = '';
for (const byte of hashArray) {
result += String.fromCharCode(byte);
}
return result;
}
private algorithmToKeyType(algorithmName: string): string {
switch (algorithmName.charAt(0)) {
case 'R':
return 'RSA';
case 'E':
return 'EC';
case 'P':
return 'RSA';
default:
throw new Error('Cannot infer key type from algorithm: ' + algorithmName);
}
}
}
+6 -26
View File
@@ -24,8 +24,7 @@
"@cspell/eslint-plugin": "9.4.0",
"@mat-datetimepicker/core": "15.0.2",
"@ngx-translate/core": "^17.0.0",
"angular-oauth2-oidc": "17.0.2",
"angular-oauth2-oidc-jwks": "^17.0.2",
"angular-oauth2-oidc": "19.0.0",
"apollo-angular": "10.0.3",
"chart.js": "4.4.4",
"cropperjs": "1.6.2",
@@ -13118,26 +13117,16 @@
}
},
"node_modules/angular-oauth2-oidc": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/angular-oauth2-oidc/-/angular-oauth2-oidc-17.0.2.tgz",
"integrity": "sha512-zYgeLmAnu1g8XAYZK+csAsCQBDhgp9ffBv/eArEnujGxNPTeK00bREHWObtehflpQdSn+k9rY2D15ChCSydyVw==",
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/angular-oauth2-oidc/-/angular-oauth2-oidc-19.0.0.tgz",
"integrity": "sha512-EogHyF7MpCJSjSKIyVmdB8pJu7dU5Ilj9VNVSnFbLng4F77PIlaE4egwKUlUvk0i4ZvmO9rLXNQCm05R7Tyhcw==",
"license": "MIT",
"dependencies": {
"tslib": "^2.5.2"
},
"peerDependencies": {
"@angular/common": ">=14.0.0",
"@angular/core": ">=14.0.0"
}
},
"node_modules/angular-oauth2-oidc-jwks": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/angular-oauth2-oidc-jwks/-/angular-oauth2-oidc-jwks-17.0.2.tgz",
"integrity": "sha512-zG0udq9VihQdCKfGjhUfrIg35TbxU34tGfOG/pddxKwJkodMAFI34cNoZoVyZ53hPgeZSDPra2rYyixkH7bkKw==",
"license": "MIT",
"dependencies": {
"jsrsasign": "^11.0.0",
"tslib": "^2.5.2"
"@angular/common": ">=19.0.0",
"@angular/core": ">=19.0.0"
}
},
"node_modules/ansi-colors": {
@@ -25470,15 +25459,6 @@
"graceful-fs": "^4.1.6"
}
},
"node_modules/jsrsasign": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-11.1.1.tgz",
"integrity": "sha512-6w95OOXH8DNeGxakqLndBEqqwQ6A70zGaky1oxfg8WVLWOnghTfJsc5Tknx+Z88MHSb1bGLcqQHImOF8Lk22XA==",
"license": "MIT",
"funding": {
"url": "https://github.com/kjur/jsrsasign#donations"
}
},
"node_modules/karma": {
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz",
+1 -2
View File
@@ -53,8 +53,7 @@
"@cspell/eslint-plugin": "9.4.0",
"@mat-datetimepicker/core": "15.0.2",
"@ngx-translate/core": "^17.0.0",
"angular-oauth2-oidc": "17.0.2",
"angular-oauth2-oidc-jwks": "^17.0.2",
"angular-oauth2-oidc": "19.0.0",
"apollo-angular": "10.0.3",
"chart.js": "4.4.4",
"cropperjs": "1.6.2",