diff --git a/README.md b/README.md index f02ea0b..e69275f 100644 --- a/README.md +++ b/README.md @@ -46,9 +46,9 @@ redirect all others to the specified url const {create_auth_handler} = require('@sapphirecode/auth-server-helper'); const handler = create_auth_handler( - (req) => { + async (req) => { if (req.user === 'foo' && req.password === 'bar') - const {access_token_id, refresh_token_id} = req.allow_access({ + const {access_token_id, refresh_token_id} = await req.allow_access({ access_token_expires_in: 600, // seconds until access tokens expire include_refresh_token: true, // should the answer include a refresh token? default: false refresh_token_expires_in: 3600, // seconds until refresh tokens expire (required if refresh tokens are generated) @@ -56,7 +56,7 @@ const handler = create_auth_handler( }); if (req.user === 'part' && req.password === 'baz') - const part_id = req.allow_part( + const part_id = await req.allow_part( 60, // seconds until part_token expires 'some_module', // next module handler (defined below) {foo: 'bar'} // custom data to attach to the token diff --git a/lib/AuthHandler.ts b/lib/AuthHandler.ts index b863a1c..3f34e30 100644 --- a/lib/AuthHandler.ts +++ b/lib/AuthHandler.ts @@ -21,7 +21,6 @@ interface AccessResult { refresh_token_id?: string; } - interface AccessResponse { token_type: string; access_token: string; @@ -69,15 +68,20 @@ class AuthRequest { this.response.setHeader ('Content-Type', 'application/json'); } - public allow_access ({ + public async allow_access ({ access_token_expires_in, include_refresh_token, refresh_token_expires_in, data - }: AccessSettings): AccessResult { + }: AccessSettings): Promise { this.default_header (); - const at = auth.sign ('access_token', access_token_expires_in, { data }); + const at = await auth.sign ( + 'access_token', + access_token_expires_in, + + { data } + ); const result: AccessResult = { access_token_id: at.id }; const res: AccessResponse = { @@ -96,7 +100,7 @@ class AuthRequest { if (include_refresh_token) { if (typeof refresh_token_expires_in !== 'number') throw new Error ('no expiry time defined for refresh tokens'); - const rt = auth.sign ( + const rt = await auth.sign ( 'refresh_token', refresh_token_expires_in, { data } @@ -111,14 +115,14 @@ class AuthRequest { return result; } - public allow_part ( + public async allow_part ( part_token_expires_in: number, next_module: string, data?: Record - ): string { + ): Promise { this.default_header (); - const pt = auth.sign ( + const pt = await auth.sign ( 'part_token', part_token_expires_in, { next_module, data } diff --git a/lib/Authority.ts b/lib/Authority.ts index ecfeb84..363c069 100644 --- a/lib/Authority.ts +++ b/lib/Authority.ts @@ -79,13 +79,13 @@ class Authority { return result; } - public sign ( + public async sign ( type: TokenType, valid_for: number, options?: SignatureOptions - ): SignatureResult { + ): Promise { const time = Date.now (); - const key = keystore.get_key (time / 1000, valid_for); + const key = await keystore.get_sign_key (time / 1000, valid_for); const attributes = { id: create_salt (), iat: time, diff --git a/lib/KeyStore.ts b/lib/KeyStore.ts index 33c43ef..bb5824e 100644 --- a/lib/KeyStore.ts +++ b/lib/KeyStore.ts @@ -5,14 +5,24 @@ * Created by Timo Hocker , December 2020 */ -import { create_salt } from '@sapphirecode/crypto-helper'; +import { generate_keypair } from '@sapphirecode/crypto-helper'; + +interface Keypair { + private_key: string; + public_key: string; +} interface Key { - key: string; + key: Keypair; valid_until: number; timeout: NodeJS.Timeout; } +function get_index (iat: number): string { + return Math.floor (iat / 60) + .toFixed (0); +} + class KeyStore { private _keys: Record = {}; @@ -22,38 +32,46 @@ class KeyStore { }, (valid_for + 5) * 1000); } - public get_key (iat: number, valid_for = 0): string { - const index = Math.floor (iat / 60) - .toFixed (0); + public async get_sign_key (iat: number, valid_for: number): Promise { + const index = get_index (iat); + + if (valid_for <= 0) + throw new Error ('cannot create infinitely valid key'); + + if ((iat + 1) * 1000 < (new Date) + .getTime ()) + throw new Error ('cannot access already expired keys'); const valid_until = (new Date) .getTime () + (valid_for * 1000); if (typeof this._keys[index] !== 'undefined') { const key = this._keys[index]; - if (valid_for !== 0 && key.valid_until < valid_until) { + if (key.valid_until < valid_until) { clearTimeout (key.timeout); key.timeout = this.set_timeout (index, valid_for); key.valid_until = valid_until; } - return key.key; + return key.key.private_key; } - if (valid_for !== 0) { - if ((iat + 1) * 1000 < (new Date) - .getTime ()) - throw new Error ('cannot create already expired keys'); + this._keys[index] = { + key: await generate_keypair (), + timeout: this.set_timeout (index, valid_for), + valid_until + }; - this._keys[index] = { - key: create_salt (), - timeout: this.set_timeout (index, valid_for), - valid_until - }; + return this._keys[index].key.private_key; + } - return this._keys[index].key; - } + public get_key (iat: number): string { + const index = get_index (iat); - throw new Error ('key could not be found'); + if (typeof this._keys[index] === 'undefined') + throw new Error ('key could not be found'); + + const key = this._keys[index]; + return key.key.public_key; } } diff --git a/package.json b/package.json index 6b5af69..da343a4 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "middleware" ], "dependencies": { - "@sapphirecode/crypto-helper": "^1.2.2", + "@sapphirecode/crypto-helper": "^1.3.0", "@sapphirecode/encoding-helper": "^1.1.0", "@sapphirecode/utilities": "^1.8.8" }, diff --git a/test/spec/Authority.ts b/test/spec/Authority.ts index 53dd482..987d50f 100644 --- a/test/spec/Authority.ts +++ b/test/spec/Authority.ts @@ -25,8 +25,8 @@ describe ('authority', () => { .uninstall (); }); - it ('should create an access token', () => { - const token = auth.sign ('access_token', 60); + it ('should create an access token', async () => { + const token = await auth.sign ('access_token', 60); jasmine.clock () .tick (30000); const res = auth.verify (token.signature); @@ -44,8 +44,8 @@ describe ('authority', () => { .toBeUndefined (); }); - it ('should create a refresh token', () => { - const token = auth.sign ('refresh_token', 600); + it ('should create a refresh token', async () => { + const token = await auth.sign ('refresh_token', 600); jasmine.clock () .tick (30000); const res = auth.verify (token.signature); @@ -63,8 +63,8 @@ describe ('authority', () => { .toBeUndefined (); }); - it ('should create a part token', () => { - const token = auth.sign ('part_token', 60, { next_module: '2fa' }); + it ('should create a part token', async () => { + const token = await auth.sign ('part_token', 60, { next_module: '2fa' }); jasmine.clock () .tick (30000); const res = auth.verify (token.signature); @@ -82,8 +82,8 @@ describe ('authority', () => { .toBeUndefined (); }); - it ('should reject an invalid access token', () => { - const token = auth.sign ('access_token', 60); + it ('should reject an invalid access token', async () => { + const token = await auth.sign ('access_token', 60); token.signature = modify_signature (token.signature); jasmine.clock () .tick (30000); @@ -102,8 +102,8 @@ describe ('authority', () => { .toEqual ('invalid signature'); }); - it ('should reject blacklisted access token', () => { - const token = auth.sign ('access_token', 60); + it ('should reject blacklisted access token', async () => { + const token = await auth.sign ('access_token', 60); jasmine.clock () .tick (30000); bl.add_signature (token.id); @@ -122,8 +122,8 @@ describe ('authority', () => { .toEqual ('blacklisted'); }); - it ('should reject an invalid refresh token', () => { - const token = auth.sign ('refresh_token', 600); + it ('should reject an invalid refresh token', async () => { + const token = await auth.sign ('refresh_token', 600); token.signature = modify_signature (token.signature); jasmine.clock () .tick (30000); @@ -142,8 +142,8 @@ describe ('authority', () => { .toEqual ('invalid signature'); }); - it ('should reject a blacklisted refresh token', () => { - const token = auth.sign ('refresh_token', 600); + it ('should reject a blacklisted refresh token', async () => { + const token = await auth.sign ('refresh_token', 600); jasmine.clock () .tick (30000); bl.add_signature (token.id); diff --git a/test/spec/Gateway.ts b/test/spec/Gateway.ts index 4fd6533..d099c03 100644 --- a/test/spec/Gateway.ts +++ b/test/spec/Gateway.ts @@ -57,7 +57,7 @@ describe ('gateway', () => { }); it ('should allow a valid access token', async () => { - const token = authority.sign ('access_token', 60); + const token = await authority.sign ('access_token', 60); const resp = await get ({ authorization: `Bearer ${token.signature}` }); expect (resp.statusCode) .toEqual (200); @@ -66,7 +66,7 @@ describe ('gateway', () => { }); it ('should allow a valid access token using cookies', async () => { - const token = authority.sign ('access_token', 60); + const token = await authority.sign ('access_token', 60); const resp = await get ({ cookie: `cookie_jar=${token.signature}` }); expect (resp.statusCode) .toEqual (200); @@ -75,7 +75,7 @@ describe ('gateway', () => { }); it ('should correctly deliver token data', async () => { - const token = authority.sign ('access_token', 60, { data: 'foobar' }); + const token = await authority.sign ('access_token', 60, { data: 'foobar' }); const resp = await get ({ authorization: `Bearer ${token.signature}` }); expect (resp.statusCode) .toEqual (200); @@ -87,7 +87,7 @@ describe ('gateway', () => { }); it ('should reject an outdated access token', async () => { - const token = authority.sign ('access_token', 60); + const token = await authority.sign ('access_token', 60); jasmine.clock () .tick (70000); const resp = await get ({ authorization: `Bearer ${token.signature}` }); @@ -98,7 +98,7 @@ describe ('gateway', () => { }); it ('should reject a blacklisted access token', async () => { - const token = authority.sign ('access_token', 60); + const token = await authority.sign ('access_token', 60); blacklist.add_signature (token.id); const resp = await get ({ authorization: `Bearer ${token.signature}` }); expect (resp.statusCode) @@ -108,7 +108,7 @@ describe ('gateway', () => { }); it ('should reject any refresh_token', async () => { - const token = authority.sign ('refresh_token', 60); + const token = await authority.sign ('refresh_token', 60); const resp = await get ({ authorization: `Bearer ${token.signature}` }); expect (resp.statusCode) .toEqual (302); @@ -117,7 +117,7 @@ describe ('gateway', () => { }); it ('should reject any part_token', async () => { - const token = authority.sign ('part_token', 60); + const token = await authority.sign ('part_token', 60); const resp = await get ({ authorization: `Bearer ${token.signature}` }); expect (resp.statusCode) .toEqual (302); @@ -126,7 +126,7 @@ describe ('gateway', () => { }); it ('should reject any noname token', async () => { - const token = authority.sign ('none', 60); + const token = await authority.sign ('none', 60); const resp = await get ({ authorization: `Bearer ${token.signature}` }); expect (resp.statusCode) .toEqual (302); diff --git a/test/spec/KeyStore.ts b/test/spec/KeyStore.ts index 6ea6efe..7b3c114 100644 --- a/test/spec/KeyStore.ts +++ b/test/spec/KeyStore.ts @@ -20,54 +20,66 @@ describe ('key store', () => { .mockDate (base_date); }); - const keys: {key:string, iat:number}[] = []; + const keys: {key:string, sign:string, iat:number}[] = []; - it ('should generate a new key', () => { + it ('should generate a new key', async () => { const iat = (new Date) .getTime () / 1000; const duration = 10 * frame; - const key = ks.get_key (iat, duration); + const key = await ks.get_sign_key (iat, duration); + const sign = ks.get_key (iat); expect (typeof key) .toEqual ('string'); - expect (key.length) - .toEqual (64); - keys.push ({ iat, key }); + expect (typeof sign) + .toEqual ('string'); + keys.push ({ iat, key, sign }); }); - it ('should return the generated key', () => { - const key = ks.get_key (keys[0].iat); + it ('should return the generated key', async () => { + const key = await ks.get_sign_key (keys[0].iat, 1); expect (key) .toEqual (keys[0].key); + const sign = ks.get_key (keys[0].iat); + expect (sign) + .toEqual (keys[0].sign); }); - it ('should return the same key on a different time', () => { - const key = ks.get_key (keys[0].iat + (frame / 2)); + it ('should return the same key on a different time', async () => { + const key = await ks.get_sign_key (keys[0].iat + (frame / 2), 1); expect (key) .toEqual (keys[0].key); + const sign = ks.get_key (keys[0].iat + (frame / 2)); + expect (sign) + .toEqual (keys[0].sign); }); - it ('should generate a new key after time frame is over', () => { + it ('should generate a new key after time frame is over', async () => { jasmine.clock () .tick (frame * 1000); const iat = (new Date) .getTime () / 1000; const duration = 10 * frame; - const key = ks.get_key (iat, duration); + const key = await ks.get_sign_key (iat, duration); + const sign = ks.get_key (iat); expect (typeof key) .toEqual ('string'); - expect (key.length) - .toEqual (64); expect (key).not.toEqual (keys[0].key); - keys.push ({ iat, key }); + expect (sign).not.toEqual (keys[0].sign); + keys.push ({ iat, key, sign }); }); - it ('should return both keys', () => { - const key = ks.get_key (keys[0].iat); - expect (key) - .toEqual (keys[0].key); - const k2 = ks.get_key (keys[1].iat); + it ('should return both keys, but not the first sign key', async () => { + const sign = ks.get_key (keys[0].iat); + expect (sign) + .toEqual (keys[0].sign); + await expectAsync (ks.get_sign_key (keys[0].iat, 1)) + .toBeRejectedWithError ('cannot access already expired keys'); + const k2 = await ks.get_sign_key (keys[1].iat, 1); + const s2 = ks.get_key (keys[1].iat); expect (k2) .toEqual (keys[1].key); + expect (s2) + .toEqual (keys[1].sign); }); it ('should throw on non existing key', () => { @@ -82,21 +94,26 @@ describe ('key store', () => { .toThrowError ('key could not be found'); }); - it ('should still retrieve the second key', () => { - const key = ks.get_key (keys[1].iat); - expect (key) - .toEqual (keys[1].key); - }); + it ( + 'should still retrieve the second key, but not its sign key', + async () => { + await expectAsync (ks.get_sign_key (keys[1].iat, 1)) + .toBeRejectedWithError ('cannot access already expired keys'); + const sign = ks.get_key (keys[1].iat); + expect (sign) + .toEqual (keys[1].sign); + } + ); - it ('should reject key generation of expired keys', () => { + it ('should reject key generation of expired keys', async () => { const iat = ((new Date) .getTime () / 1000) - 2; const duration = 5; - expect (() => ks.get_key (iat, duration)) - .toThrowError ('cannot create already expired keys'); + await expectAsync (ks.get_sign_key (iat, duration)) + .toBeRejectedWithError ('cannot access already expired keys'); }); - it ('key should live as long as the longest created token', () => { + it ('key should live as long as the longest created token', async () => { const base = new Date; base.setSeconds (2, 0); jasmine.clock () @@ -108,21 +125,22 @@ describe ('key store', () => { const duration1 = frame; const duration2 = frame * 10; - const key1 = ks.get_key (iat, duration1); + const key1 = await ks.get_sign_key (iat, duration1); const step = 0.9 * frame; jasmine.clock () .tick (step * 1000); - const key2 = ks.get_key (iat + step, duration2); + const key2 = await ks.get_sign_key (iat + step, duration2); + const sign = ks.get_key (iat); expect (key1) .toEqual (key2); jasmine.clock () .tick (5000 * frame); - const keyv = ks.get_key (iat + step); - expect (keyv) - .toEqual (key1); + const signv = ks.get_key (iat + step); + expect (signv) + .toEqual (sign); }); - // required use case: insert keys for verification of old tokens + // TODO: required use case: insert keys for verification of old tokens afterAll (() => { jasmine.clock () diff --git a/yarn.lock b/yarn.lock index ff52911..b3b5625 100644 --- a/yarn.lock +++ b/yarn.lock @@ -329,10 +329,10 @@ "@nodelib/fs.scandir" "2.1.4" fastq "^1.6.0" -"@sapphirecode/crypto-helper@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@sapphirecode/crypto-helper/-/crypto-helper-1.2.2.tgz#518c763ed069f78850a05c92326672ec8f398ef5" - integrity sha512-OOHKrbD+YHriqkLk8snOJWTskmptmImTZH62Q09XeHbit09zSMUSk+B5c5eyPr80L1s7SSETqfNx7iyIAWKQzg== +"@sapphirecode/crypto-helper@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@sapphirecode/crypto-helper/-/crypto-helper-1.3.0.tgz#3d46878475064327af19779afabb6776e3b339c5" + integrity sha512-v3fSYKxYV/QZYGNcb977ZNzTgRrjmAVus8H01Jpc/vJN1mKbR6gwb4mL3oHQWJ0JjWlz2+lTKZ160fTr02le5g== dependencies: "@sapphirecode/encoding-helper" "^1.1.0" @@ -469,60 +469,60 @@ integrity sha512-vwX+/ija9xKc/z9VqMCdbf4WYcMTGsI0I/L/6shIF3qXURxZOhPQlPRHtjTpiNhAwn0paMJzlOQqw6mAGEQnTA== "@typescript-eslint/eslint-plugin@^4.1.0": - version "4.11.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.11.1.tgz#7579c6d17ad862154c10bc14b40e5427b729e209" - integrity sha512-fABclAX2QIEDmTMk6Yd7Muv1CzFLwWM4505nETzRHpP3br6jfahD9UUJkhnJ/g2m7lwfz8IlswcwGGPGiq9exw== + version "4.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.12.0.tgz#00d1b23b40b58031e6d7c04a5bc6c1a30a2e834a" + integrity sha512-wHKj6q8s70sO5i39H2g1gtpCXCvjVszzj6FFygneNFyIAxRvNSVz9GML7XpqrB9t7hNutXw+MHnLN/Ih6uyB8Q== dependencies: - "@typescript-eslint/experimental-utils" "4.11.1" - "@typescript-eslint/scope-manager" "4.11.1" + "@typescript-eslint/experimental-utils" "4.12.0" + "@typescript-eslint/scope-manager" "4.12.0" debug "^4.1.1" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@4.11.1": - version "4.11.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.11.1.tgz#2dad3535b878c25c7424e40bfa79d899f3f485bc" - integrity sha512-mAlWowT4A6h0TC9F+J5pdbEhjNiEMO+kqPKQ4sc3fVieKL71dEqfkKgtcFVSX3cjSBwYwhImaQ/mXQF0oaI38g== +"@typescript-eslint/experimental-utils@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.12.0.tgz#372838e76db76c9a56959217b768a19f7129546b" + integrity sha512-MpXZXUAvHt99c9ScXijx7i061o5HEjXltO+sbYfZAAHxv3XankQkPaNi5myy0Yh0Tyea3Hdq1pi7Vsh0GJb0fA== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.11.1" - "@typescript-eslint/types" "4.11.1" - "@typescript-eslint/typescript-estree" "4.11.1" + "@typescript-eslint/scope-manager" "4.12.0" + "@typescript-eslint/types" "4.12.0" + "@typescript-eslint/typescript-estree" "4.12.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" "@typescript-eslint/parser@^4.1.0": - version "4.11.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.11.1.tgz#981e18de2e019d6ca312596615f92e8f6f6598ed" - integrity sha512-BJ3jwPQu1jeynJ5BrjLuGfK/UJu6uwHxJ/di7sanqmUmxzmyIcd3vz58PMR7wpi8k3iWq2Q11KMYgZbUpRoIPw== + version "4.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.12.0.tgz#e1cf30436e4f916c31fcc962158917bd9e9d460a" + integrity sha512-9XxVADAo9vlfjfoxnjboBTxYOiNY93/QuvcPgsiKvHxW6tOZx1W4TvkIQ2jB3k5M0pbFP5FlXihLK49TjZXhuQ== dependencies: - "@typescript-eslint/scope-manager" "4.11.1" - "@typescript-eslint/types" "4.11.1" - "@typescript-eslint/typescript-estree" "4.11.1" + "@typescript-eslint/scope-manager" "4.12.0" + "@typescript-eslint/types" "4.12.0" + "@typescript-eslint/typescript-estree" "4.12.0" debug "^4.1.1" -"@typescript-eslint/scope-manager@4.11.1": - version "4.11.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.11.1.tgz#72dc2b60b0029ab0888479b12bf83034920b4b69" - integrity sha512-Al2P394dx+kXCl61fhrrZ1FTI7qsRDIUiVSuN6rTwss6lUn8uVO2+nnF4AvO0ug8vMsy3ShkbxLu/uWZdTtJMQ== +"@typescript-eslint/scope-manager@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.12.0.tgz#beeb8beca895a07b10c593185a5612f1085ef279" + integrity sha512-QVf9oCSVLte/8jvOsxmgBdOaoe2J0wtEmBr13Yz0rkBNkl5D8bfnf6G4Vhox9qqMIoG7QQoVwd2eG9DM/ge4Qg== dependencies: - "@typescript-eslint/types" "4.11.1" - "@typescript-eslint/visitor-keys" "4.11.1" + "@typescript-eslint/types" "4.12.0" + "@typescript-eslint/visitor-keys" "4.12.0" -"@typescript-eslint/types@4.11.1": - version "4.11.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.11.1.tgz#3ba30c965963ef9f8ced5a29938dd0c465bd3e05" - integrity sha512-5kvd38wZpqGY4yP/6W3qhYX6Hz0NwUbijVsX2rxczpY6OXaMxh0+5E5uLJKVFwaBM7PJe1wnMym85NfKYIh6CA== +"@typescript-eslint/types@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.12.0.tgz#fb891fe7ccc9ea8b2bbd2780e36da45d0dc055e5" + integrity sha512-N2RhGeheVLGtyy+CxRmxdsniB7sMSCfsnbh8K/+RUIXYYq3Ub5+sukRCjVE80QerrUBvuEvs4fDhz5AW/pcL6g== -"@typescript-eslint/typescript-estree@4.11.1": - version "4.11.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.11.1.tgz#a4416b4a65872a48773b9e47afabdf7519eb10bc" - integrity sha512-tC7MKZIMRTYxQhrVAFoJq/DlRwv1bnqA4/S2r3+HuHibqvbrPcyf858lNzU7bFmy4mLeIHFYr34ar/1KumwyRw== +"@typescript-eslint/typescript-estree@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.12.0.tgz#3963418c850f564bdab3882ae23795d115d6d32e" + integrity sha512-gZkFcmmp/CnzqD2RKMich2/FjBTsYopjiwJCroxqHZIY11IIoN0l5lKqcgoAPKHt33H2mAkSfvzj8i44Jm7F4w== dependencies: - "@typescript-eslint/types" "4.11.1" - "@typescript-eslint/visitor-keys" "4.11.1" + "@typescript-eslint/types" "4.12.0" + "@typescript-eslint/visitor-keys" "4.12.0" debug "^4.1.1" globby "^11.0.1" is-glob "^4.0.1" @@ -530,12 +530,12 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/visitor-keys@4.11.1": - version "4.11.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.1.tgz#4c050a4c1f7239786e2dd4e69691436143024e05" - integrity sha512-IrlBhD9bm4bdYcS8xpWarazkKXlE7iYb1HzRuyBP114mIaj5DJPo11Us1HgH60dTt41TCZXMaTCAW+OILIYPOg== +"@typescript-eslint/visitor-keys@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.12.0.tgz#a470a79be6958075fa91c725371a83baf428a67a" + integrity sha512-hVpsLARbDh4B9TKYz5cLbcdMIOAoBYgFPCSP9FFS/liSF+b33gVNq8JHY3QGhHNVz85hObvL7BEYLlgx553WCw== dependencies: - "@typescript-eslint/types" "4.11.1" + "@typescript-eslint/types" "4.12.0" eslint-visitor-keys "^2.0.0" acorn-jsx@^5.3.1: @@ -566,6 +566,16 @@ ajv@^6.10.0, ajv@^6.12.4, ajv@~6.12.0, ajv@~6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.0.3.tgz#13ae747eff125cafb230ac504b2406cf371eece2" + integrity sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + angular-html-parser@~1.7.0: version "1.7.1" resolved "https://registry.yarnpkg.com/angular-html-parser/-/angular-html-parser-1.7.1.tgz#735cb9f2f01151e6d612b580812256a289e728a4" @@ -1077,9 +1087,9 @@ eslint-visitor-keys@^2.0.0: integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== eslint@^7.14.0: - version "7.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.16.0.tgz#a761605bf9a7b32d24bb7cde59aeb0fd76f06092" - integrity sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw== + version "7.17.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.17.0.tgz#4ccda5bf12572ad3bf760e6f195886f50569adb0" + integrity sha512-zJk08MiBgwuGoxes5sSQhOtibZ75pz0J35XTRlZOk9xMffhpA9BTbQZxoXZzOl5zMbleShbGwtw+1kGferfFwQ== dependencies: "@babel/code-frame" "^7.0.0" "@eslint/eslintrc" "^0.2.2" @@ -1393,9 +1403,9 @@ globals@^12.1.0: type-fest "^0.8.1" globby@^11.0.1: - version "11.0.1" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" - integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== + version "11.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83" + integrity sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og== dependencies: array-union "^2.1.0" dir-glob "^3.0.1" @@ -1716,6 +1726,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -2211,6 +2226,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -2491,11 +2511,11 @@ surrial@~2.0.2: integrity sha512-YQ0XyrdBI8Kx10lIK81zOGXdGtc0P+3FTqEtCdaKzfEJKJWDju2QPp+XhzihmN2KOTRDtkKSyQQXZHYP+SqapA== table@^6.0.4: - version "6.0.4" - resolved "https://registry.yarnpkg.com/table/-/table-6.0.4.tgz#c523dd182177e926c723eb20e1b341238188aa0d" - integrity sha512-sBT4xRLdALd+NFBvwOz8bw4b15htyythha+q+DVZqy2RS08PPC8O2sZFgJYEY7bJvbCFKccs+WIZ/cd+xxTWCw== + version "6.0.7" + resolved "https://registry.yarnpkg.com/table/-/table-6.0.7.tgz#e45897ffbcc1bcf9e8a87bf420f2c9e5a7a52a34" + integrity sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g== dependencies: - ajv "^6.12.4" + ajv "^7.0.2" lodash "^4.17.20" slice-ansi "^4.0.0" string-width "^4.2.0" @@ -2576,9 +2596,9 @@ tslib@~2.0.0: integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ== tsutils@^3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" - integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + version "3.18.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.18.0.tgz#38add50a28ec97e988cb43c5b32e55d1ff4a222a" + integrity sha512-D9Tu8nE3E7D1Bsf/V29oMHceMf+gnVO+pDguk/A5YRo1cLpkiQ48ZnbbS57pvvHeY+OIeNQx1vf4ASPlEtRpcA== dependencies: tslib "^1.8.1"