Auto-commit 2026-04-29 16:31
This commit is contained in:
21
node_modules/openid-client/LICENSE.md
generated
vendored
Normal file
21
node_modules/openid-client/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Filip Skokan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
320
node_modules/openid-client/README.md
generated
vendored
Normal file
320
node_modules/openid-client/README.md
generated
vendored
Normal file
@@ -0,0 +1,320 @@
|
||||
# openid-client
|
||||
|
||||
openid-client is a server side [OpenID][openid-connect] Relying Party (RP, Client) implementation for
|
||||
Node.js runtime, supports [passport][passport-url].
|
||||
|
||||
## Implemented specs & features
|
||||
|
||||
The following client/RP features from OpenID Connect/OAuth2.0 specifications are implemented by
|
||||
openid-client.
|
||||
|
||||
- [OpenID Connect Core 1.0][feature-core]
|
||||
- Authorization Callback
|
||||
- Authorization Code Flow
|
||||
- Implicit Flow
|
||||
- Hybrid Flow
|
||||
- UserInfo Request
|
||||
- Offline Access / Refresh Token Grant
|
||||
- Client Credentials Grant
|
||||
- Client Authentication
|
||||
- none
|
||||
- client_secret_basic
|
||||
- client_secret_post
|
||||
- client_secret_jwt
|
||||
- private_key_jwt
|
||||
- Consuming Self-Issued OpenID Provider ID Token response
|
||||
- [OpenID Connect Discovery 1.0][feature-discovery]
|
||||
- Discovery of OpenID Provider (Issuer) Metadata
|
||||
- Discovery of OpenID Provider (Issuer) Metadata via user provided inputs (via [webfinger][documentation-webfinger])
|
||||
- [OpenID Connect Dynamic Client Registration 1.0][feature-registration]
|
||||
- Dynamic Client Registration request
|
||||
- Client initialization via registration client uri
|
||||
- [RFC7009 - OAuth 2.0 Token revocation][feature-revocation]
|
||||
- Client Authenticated request to token revocation
|
||||
- [RFC7662 - OAuth 2.0 Token introspection][feature-introspection]
|
||||
- Client Authenticated request to token introspection
|
||||
- [RFC8628 - OAuth 2.0 Device Authorization Grant (Device Flow)][feature-device-flow]
|
||||
- [RFC8705 - OAuth 2.0 Mutual TLS Client Authentication and Certificate-Bound Access Tokens][feature-mtls]
|
||||
- Mutual TLS Client Certificate-Bound Access Tokens
|
||||
- Metadata for Mutual TLS Endpoint Aliases
|
||||
- Client Authentication
|
||||
- tls_client_auth
|
||||
- self_signed_tls_client_auth
|
||||
- [RFC9101 - OAuth 2.0 JWT-Secured Authorization Request (JAR)][feature-jar]
|
||||
- [RFC9126 - OAuth 2.0 Pushed Authorization Requests (PAR)][feature-par]
|
||||
- [RFC9449 - OAuth 2.0 Demonstration of Proof-of-Possession at the Application Layer (DPoP)][feature-dpop]
|
||||
- [OpenID Connect RP-Initiated Logout 1.0][feature-rp-logout]
|
||||
- [Financial-grade API Security Profile 1.0 - Part 2: Advanced (FAPI)][feature-fapi]
|
||||
- [JWT Secured Authorization Response Mode for OAuth 2.0 (JARM)][feature-jarm]
|
||||
- [OAuth 2.0 Authorization Server Issuer Identification][feature-iss]
|
||||
|
||||
Updates to draft specifications are released as MINOR library versions,
|
||||
if you utilize these specification implementations consider using the tilde `~` operator in your
|
||||
package.json since breaking changes may be introduced as part of these version updates.
|
||||
|
||||
## [Certification](https://openid.net/certification/faq/)
|
||||
|
||||
[<img width="96" height="50" align="right" src="https://user-images.githubusercontent.com/241506/166977513-7cd710a9-7f60-4944-aebe-a658e9f36375.png" alt="OpenID Certification">](#certification)
|
||||
|
||||
[Filip Skokan](https://github.com/panva) has [certified](https://openid.net/certification) that [this software](https://github.com/panva/node-openid-client) conforms to the Basic, Implicit, Hybrid, Config, Dynamic, FAPI 1.0, and FAPI 2.0 Relying Party Conformance Profiles of the OpenID Connect™ protocol.
|
||||
|
||||
## Sponsor
|
||||
|
||||
[<img height="65" align="left" src="https://cdn.auth0.com/blog/github-sponsorships/brand-evolution-logo-Auth0-horizontal-Indigo.png" alt="auth0-logo">][sponsor-auth0] If you want to quickly add OpenID Connect authentication to Node.js apps, feel free to check out Auth0's Node.js SDK and free plan. [Create an Auth0 account; it's free!][sponsor-auth0]<br><br>
|
||||
|
||||
## Support
|
||||
|
||||
If you or your business use openid-client, please consider becoming a [sponsor][support-sponsor] so I can continue maintaining it and adding new features carefree.
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
The library exposes what are essentially steps necessary to be done by a relying party consuming
|
||||
OpenID Connect Authorization Server responses or wrappers around requests to its endpoints. Aside
|
||||
from a generic OpenID Connect [passport][passport-url] strategy it does not expose any framework
|
||||
specific middlewares. Those can however be built using the exposed API, one such example is [express-openid-connect][]
|
||||
|
||||
- [openid-client API Documentation][documentation]
|
||||
- [Issuer][documentation-issuer]
|
||||
- [Client][documentation-client]
|
||||
- [Customizing][documentation-customizing]
|
||||
- [TokenSet][documentation-tokenset]
|
||||
- [Strategy][documentation-strategy]
|
||||
- [generators][documentation-generators]
|
||||
- [errors][documentation-errors]
|
||||
|
||||
## Install
|
||||
|
||||
Node.js LTS releases Codename Erbium and newer LTS releases are supported.
|
||||
|
||||
```console
|
||||
npm install openid-client
|
||||
```
|
||||
|
||||
Note: Other javascript runtimes are not supported.
|
||||
I recommend [panva/oauth4webapi][oauth4webapi], or a derivate thereof, if you're
|
||||
looking for a similarly compliant and certified client software that's not dependent
|
||||
on the Node.js runtime builtins.
|
||||
|
||||
## Quick start
|
||||
|
||||
Discover an Issuer configuration using its published .well-known endpoints
|
||||
```js
|
||||
import { Issuer } from 'openid-client';
|
||||
|
||||
const googleIssuer = await Issuer.discover('https://accounts.google.com');
|
||||
console.log('Discovered issuer %s %O', googleIssuer.issuer, googleIssuer.metadata);
|
||||
```
|
||||
|
||||
### Authorization Code Flow
|
||||
|
||||
Authorization Code flow is for obtaining Access Tokens (and optionally Refresh Tokens) to use with
|
||||
third party APIs securely as well as Refresh Tokens. In this quick start your application also uses
|
||||
PKCE instead of `state` parameter for CSRF protection.
|
||||
|
||||
Create a Client instance for that issuer's authorization server intended for Authorization Code
|
||||
flow.
|
||||
|
||||
**See the [documentation][] for full API details.**
|
||||
|
||||
```js
|
||||
const client = new googleIssuer.Client({
|
||||
client_id: 'zELcpfANLqY7Oqas',
|
||||
client_secret: 'TQV5U29k1gHibH5bx1layBo0OSAvAbRT3UYW3EWrSYBB5swxjVfWUa1BS8lqzxG/0v9wruMcrGadany3',
|
||||
redirect_uris: ['http://localhost:3000/cb'],
|
||||
response_types: ['code'],
|
||||
// id_token_signed_response_alg (default "RS256")
|
||||
// token_endpoint_auth_method (default "client_secret_basic")
|
||||
}); // => Client
|
||||
```
|
||||
|
||||
When you want to have your end-users authorize you need to send them to the issuer's
|
||||
`authorization_endpoint`. Consult the web framework of your choice on how to redirect but here's how
|
||||
to get the authorization endpoint's URL with parameters already encoded in the query to redirect
|
||||
to.
|
||||
|
||||
```js
|
||||
import { generators } from 'openid-client';
|
||||
const code_verifier = generators.codeVerifier();
|
||||
// store the code_verifier in your framework's session mechanism, if it is a cookie based solution
|
||||
// it should be httpOnly (not readable by javascript) and encrypted.
|
||||
|
||||
const code_challenge = generators.codeChallenge(code_verifier);
|
||||
|
||||
client.authorizationUrl({
|
||||
scope: 'openid email profile',
|
||||
resource: 'https://my.api.example.com/resource/32178',
|
||||
code_challenge,
|
||||
code_challenge_method: 'S256',
|
||||
});
|
||||
```
|
||||
|
||||
When end-users are redirected back to your `redirect_uri` your application consumes the callback and
|
||||
passes in the `code_verifier` to include it in the authorization code grant token exchange.
|
||||
```js
|
||||
const params = client.callbackParams(req);
|
||||
const tokenSet = await client.callback('https://client.example.com/callback', params, { code_verifier });
|
||||
console.log('received and validated tokens %j', tokenSet);
|
||||
console.log('validated ID Token claims %j', tokenSet.claims());
|
||||
```
|
||||
|
||||
You can then call the `userinfo_endpoint`.
|
||||
```js
|
||||
const userinfo = await client.userinfo(access_token);
|
||||
console.log('userinfo %j', userinfo);
|
||||
```
|
||||
|
||||
And later refresh the tokenSet if it had a `refresh_token`.
|
||||
```js
|
||||
const tokenSet = await client.refresh(refresh_token);
|
||||
console.log('refreshed and validated tokens %j', tokenSet);
|
||||
console.log('refreshed ID Token claims %j', tokenSet.claims());
|
||||
```
|
||||
|
||||
### Implicit ID Token Flow
|
||||
|
||||
Implicit `response_type=id_token` flow is perfect for simply authenticating your end-users, assuming
|
||||
the only job you want done is authenticating the user and then relying on your own session mechanism
|
||||
with no need for accessing any third party APIs with an Access Token from the Authorization Server.
|
||||
|
||||
Create a Client instance for that issuer's authorization server intended for ID Token implicit flow.
|
||||
|
||||
**See the [documentation][] for full API details.**
|
||||
```js
|
||||
const client = new googleIssuer.Client({
|
||||
client_id: 'zELcpfANLqY7Oqas',
|
||||
redirect_uris: ['http://localhost:3000/cb'],
|
||||
response_types: ['id_token'],
|
||||
// id_token_signed_response_alg (default "RS256")
|
||||
}); // => Client
|
||||
```
|
||||
|
||||
When you want to have your end-users authorize you need to send them to the issuer's
|
||||
`authorization_endpoint`. Consult the web framework of your choice on how to redirect but here's how
|
||||
to get the authorization endpoint's URL with parameters already encoded in the query to redirect
|
||||
to.
|
||||
|
||||
```js
|
||||
import { generators } from 'openid-client';
|
||||
const nonce = generators.nonce();
|
||||
// store the nonce in your framework's session mechanism, if it is a cookie based solution
|
||||
// it should be httpOnly (not readable by javascript) and encrypted.
|
||||
|
||||
client.authorizationUrl({
|
||||
scope: 'openid email profile',
|
||||
response_mode: 'form_post',
|
||||
nonce,
|
||||
});
|
||||
```
|
||||
|
||||
When end-users hit back your `redirect_uri` with a POST (authorization request included `form_post`
|
||||
response mode) your application consumes the callback and passes the `nonce` in to include it in the
|
||||
ID Token verification steps.
|
||||
```js
|
||||
// assumes req.body is populated from your web framework's body parser
|
||||
const params = client.callbackParams(req);
|
||||
const tokenSet = await client.callback('https://client.example.com/callback', params, { nonce });
|
||||
console.log('received and validated tokens %j', tokenSet);
|
||||
console.log('validated ID Token claims %j', tokenSet.claims());
|
||||
```
|
||||
|
||||
### Device Authorization Grant (Device Flow)
|
||||
|
||||
[RFC8628 - OAuth 2.0 Device Authorization Grant (Device Flow)](https://tools.ietf.org/html/rfc8628)
|
||||
is started by starting a Device Authorization Request.
|
||||
|
||||
```js
|
||||
const handle = await client.deviceAuthorization();
|
||||
console.log('User Code: ', handle.user_code);
|
||||
console.log('Verification URI: ', handle.verification_uri);
|
||||
console.log('Verification URI (complete): ', handle.verification_uri_complete);
|
||||
```
|
||||
|
||||
The handle represents a Device Authorization Response with the `verification_uri`, `user_code` and
|
||||
other defined response properties.
|
||||
|
||||
You will display the instructions to the end-user and have him directed at `verification_uri` or
|
||||
`verification_uri_complete`, afterwards you can start polling for the Device Access Token Response.
|
||||
```js
|
||||
const tokenSet = await handle.poll();
|
||||
console.log('received tokens %j', tokenSet);
|
||||
```
|
||||
|
||||
This will poll in the defined interval and only resolve with a TokenSet once one is received. This
|
||||
will handle the defined `authorization_pending` and `slow_down` "soft" errors and continue polling
|
||||
but upon any other error it will reject. With tokenSet received you can throw away the handle.
|
||||
|
||||
### Client Credentials Grant Flow
|
||||
|
||||
Client Credentials flow is for obtaining Access Tokens to use with third party APIs on behalf of your application, rather than an end-user which was the case in previous examples.
|
||||
|
||||
**See the [documentation](./docs/README.md#clientgrantbody-extras) for full API details.**
|
||||
|
||||
```js
|
||||
const client = new issuer.Client({
|
||||
client_id: 'zELcpfANLqY7Oqas',
|
||||
client_secret: 'TQV5U29k1gHibH5bx1layBo0OSAvAbRT3UYW3EWrSYBB5swxjVfWUa1BS8lqzxG/0v9wruMcrGadany3',
|
||||
});
|
||||
|
||||
const tokenSet = await client.grant({
|
||||
resource: 'urn:example:third-party-api',
|
||||
grant_type: 'client_credentials'
|
||||
});
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
#### Semver?
|
||||
|
||||
**Yes.** Everything that's either exported in the TypeScript definitions file or
|
||||
[documented][documentation] is subject to
|
||||
[Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html). The rest is to be considered
|
||||
private API and is subject to change between any versions.
|
||||
|
||||
#### How do I use it outside of Node.js
|
||||
|
||||
It is **only built for Node.js**. Other javascript runtimes are not supported.
|
||||
I recommend [panva/oauth4webapi][oauth4webapi], or a derivate thereof, if you're
|
||||
looking for a similarly compliant and certified client software that's not dependent
|
||||
on the Node.js runtime builtins.
|
||||
|
||||
#### How to make the client send client_id and client_secret in the body?
|
||||
|
||||
See [Client Authentication Methods (docs)][documentation-methods].
|
||||
|
||||
#### Can I adjust the HTTP timeout?
|
||||
|
||||
See [Customizing (docs)][documentation-customizing].
|
||||
|
||||
|
||||
[openid-connect]: https://openid.net/connect/
|
||||
[feature-core]: https://openid.net/specs/openid-connect-core-1_0.html
|
||||
[feature-discovery]: https://openid.net/specs/openid-connect-discovery-1_0.html
|
||||
[feature-registration]: https://openid.net/specs/openid-connect-registration-1_0.html
|
||||
[feature-revocation]: https://tools.ietf.org/html/rfc7009
|
||||
[feature-introspection]: https://tools.ietf.org/html/rfc7662
|
||||
[feature-mtls]: https://tools.ietf.org/html/rfc8705
|
||||
[feature-device-flow]: https://tools.ietf.org/html/rfc8628
|
||||
[feature-rp-logout]: https://openid.net/specs/openid-connect-rpinitiated-1_0.html
|
||||
[feature-jarm]: https://openid.net/specs/oauth-v2-jarm.html
|
||||
[feature-fapi]: https://openid.net/specs/openid-financial-api-part-2-1_0.html
|
||||
[feature-dpop]: https://www.rfc-editor.org/rfc/rfc9449.html
|
||||
[feature-par]: https://www.rfc-editor.org/rfc/rfc9126.html
|
||||
[feature-jar]: https://www.rfc-editor.org/rfc/rfc9101.html
|
||||
[feature-iss]: https://www.rfc-editor.org/rfc/rfc9207.html
|
||||
[passport-url]: http://passportjs.org
|
||||
[npm-url]: https://www.npmjs.com/package/openid-client
|
||||
[sponsor-auth0]: https://a0.to/try-auth0
|
||||
[support-sponsor]: https://github.com/sponsors/panva
|
||||
[documentation]: https://github.com/panva/node-openid-client/blob/main/docs/README.md
|
||||
[documentation-issuer]: https://github.com/panva/node-openid-client/blob/main/docs/README.md#issuer
|
||||
[documentation-client]: https://github.com/panva/node-openid-client/blob/main/docs/README.md#client
|
||||
[documentation-customizing]: https://github.com/panva/node-openid-client/blob/main/docs/README.md#customizing
|
||||
[documentation-tokenset]: https://github.com/panva/node-openid-client/blob/main/docs/README.md#tokenset
|
||||
[documentation-strategy]: https://github.com/panva/node-openid-client/blob/main/docs/README.md#strategy
|
||||
[documentation-errors]: https://github.com/panva/node-openid-client/blob/main/docs/README.md#errors
|
||||
[documentation-generators]: https://github.com/panva/node-openid-client/blob/main/docs/README.md#generators
|
||||
[documentation-methods]: https://github.com/panva/node-openid-client/blob/main/docs/README.md#client-authentication-methods
|
||||
[documentation-webfinger]: https://github.com/panva/node-openid-client/blob/main/docs/README.md#issuerwebfingerinput
|
||||
[express-openid-connect]: https://www.npmjs.com/package/express-openid-connect
|
||||
[oauth4webapi]: https://github.com/panva/oauth4webapi#readme
|
||||
1884
node_modules/openid-client/lib/client.js
generated
vendored
Normal file
1884
node_modules/openid-client/lib/client.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
125
node_modules/openid-client/lib/device_flow_handle.js
generated
vendored
Normal file
125
node_modules/openid-client/lib/device_flow_handle.js
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
const { inspect } = require('util');
|
||||
|
||||
const { RPError, OPError } = require('./errors');
|
||||
const now = require('./helpers/unix_timestamp');
|
||||
|
||||
class DeviceFlowHandle {
|
||||
#aborted;
|
||||
#client;
|
||||
#clientAssertionPayload;
|
||||
#DPoP;
|
||||
#exchangeBody;
|
||||
#expires_at;
|
||||
#interval;
|
||||
#maxAge;
|
||||
#response;
|
||||
constructor({ client, exchangeBody, clientAssertionPayload, response, maxAge, DPoP }) {
|
||||
['verification_uri', 'user_code', 'device_code'].forEach((prop) => {
|
||||
if (typeof response[prop] !== 'string' || !response[prop]) {
|
||||
throw new RPError(
|
||||
`expected ${prop} string to be returned by Device Authorization Response, got %j`,
|
||||
response[prop],
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (!Number.isSafeInteger(response.expires_in)) {
|
||||
throw new RPError(
|
||||
'expected expires_in number to be returned by Device Authorization Response, got %j',
|
||||
response.expires_in,
|
||||
);
|
||||
}
|
||||
|
||||
this.#expires_at = now() + response.expires_in;
|
||||
this.#client = client;
|
||||
this.#DPoP = DPoP;
|
||||
this.#maxAge = maxAge;
|
||||
this.#exchangeBody = exchangeBody;
|
||||
this.#clientAssertionPayload = clientAssertionPayload;
|
||||
this.#response = response;
|
||||
this.#interval = response.interval * 1000 || 5000;
|
||||
}
|
||||
|
||||
abort() {
|
||||
this.#aborted = true;
|
||||
}
|
||||
|
||||
async poll({ signal } = {}) {
|
||||
if ((signal && signal.aborted) || this.#aborted) {
|
||||
throw new RPError('polling aborted');
|
||||
}
|
||||
|
||||
if (this.expired()) {
|
||||
throw new RPError(
|
||||
'the device code %j has expired and the device authorization session has concluded',
|
||||
this.device_code,
|
||||
);
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, this.#interval));
|
||||
|
||||
let tokenset;
|
||||
try {
|
||||
tokenset = await this.#client.grant(
|
||||
{
|
||||
...this.#exchangeBody,
|
||||
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
||||
device_code: this.device_code,
|
||||
},
|
||||
{ clientAssertionPayload: this.#clientAssertionPayload, DPoP: this.#DPoP },
|
||||
);
|
||||
} catch (err) {
|
||||
switch (err instanceof OPError && err.error) {
|
||||
case 'slow_down':
|
||||
this.#interval += 5000;
|
||||
case 'authorization_pending':
|
||||
return this.poll({ signal });
|
||||
default:
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
if ('id_token' in tokenset) {
|
||||
await this.#client.decryptIdToken(tokenset);
|
||||
await this.#client.validateIdToken(tokenset, undefined, 'token', this.#maxAge);
|
||||
}
|
||||
|
||||
return tokenset;
|
||||
}
|
||||
|
||||
get device_code() {
|
||||
return this.#response.device_code;
|
||||
}
|
||||
|
||||
get user_code() {
|
||||
return this.#response.user_code;
|
||||
}
|
||||
|
||||
get verification_uri() {
|
||||
return this.#response.verification_uri;
|
||||
}
|
||||
|
||||
get verification_uri_complete() {
|
||||
return this.#response.verification_uri_complete;
|
||||
}
|
||||
|
||||
get expires_in() {
|
||||
return Math.max.apply(null, [this.#expires_at - now(), 0]);
|
||||
}
|
||||
|
||||
expired() {
|
||||
return this.expires_in === 0;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
[inspect.custom]() {
|
||||
return `${this.constructor.name} ${inspect(this.#response, {
|
||||
depth: Infinity,
|
||||
colors: process.stdout.isTTY,
|
||||
compact: false,
|
||||
sorted: true,
|
||||
})}`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DeviceFlowHandle;
|
||||
55
node_modules/openid-client/lib/errors.js
generated
vendored
Normal file
55
node_modules/openid-client/lib/errors.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
const { format } = require('util');
|
||||
|
||||
class OPError extends Error {
|
||||
constructor({ error_description, error, error_uri, session_state, state, scope }, response) {
|
||||
super(!error_description ? error : `${error} (${error_description})`);
|
||||
|
||||
Object.assign(
|
||||
this,
|
||||
{ error },
|
||||
error_description && { error_description },
|
||||
error_uri && { error_uri },
|
||||
state && { state },
|
||||
scope && { scope },
|
||||
session_state && { session_state },
|
||||
);
|
||||
|
||||
if (response) {
|
||||
Object.defineProperty(this, 'response', {
|
||||
value: response,
|
||||
});
|
||||
}
|
||||
|
||||
this.name = this.constructor.name;
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
}
|
||||
|
||||
class RPError extends Error {
|
||||
constructor(...args) {
|
||||
if (typeof args[0] === 'string') {
|
||||
super(format(...args));
|
||||
} else {
|
||||
const { message, printf, response, ...rest } = args[0];
|
||||
if (printf) {
|
||||
super(format(...printf));
|
||||
} else {
|
||||
super(message);
|
||||
}
|
||||
Object.assign(this, rest);
|
||||
if (response) {
|
||||
Object.defineProperty(this, 'response', {
|
||||
value: response,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.name = this.constructor.name;
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
OPError,
|
||||
RPError,
|
||||
};
|
||||
24
node_modules/openid-client/lib/helpers/assert.js
generated
vendored
Normal file
24
node_modules/openid-client/lib/helpers/assert.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
function assertSigningAlgValuesSupport(endpoint, issuer, properties) {
|
||||
if (!issuer[`${endpoint}_endpoint`]) return;
|
||||
|
||||
const eam = `${endpoint}_endpoint_auth_method`;
|
||||
const easa = `${endpoint}_endpoint_auth_signing_alg`;
|
||||
const easavs = `${endpoint}_endpoint_auth_signing_alg_values_supported`;
|
||||
|
||||
if (properties[eam] && properties[eam].endsWith('_jwt') && !properties[easa] && !issuer[easavs]) {
|
||||
throw new TypeError(
|
||||
`${easavs} must be configured on the issuer if ${easa} is not defined on a client`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function assertIssuerConfiguration(issuer, endpoint) {
|
||||
if (!issuer[endpoint]) {
|
||||
throw new TypeError(`${endpoint} must be configured on the issuer`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
assertSigningAlgValuesSupport,
|
||||
assertIssuerConfiguration,
|
||||
};
|
||||
13
node_modules/openid-client/lib/helpers/base64url.js
generated
vendored
Normal file
13
node_modules/openid-client/lib/helpers/base64url.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
let encode;
|
||||
if (Buffer.isEncoding('base64url')) {
|
||||
encode = (input, encoding = 'utf8') => Buffer.from(input, encoding).toString('base64url');
|
||||
} else {
|
||||
const fromBase64 = (base64) => base64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
|
||||
encode = (input, encoding = 'utf8') =>
|
||||
fromBase64(Buffer.from(input, encoding).toString('base64'));
|
||||
}
|
||||
|
||||
const decode = (input) => Buffer.from(input, 'base64');
|
||||
|
||||
module.exports.decode = decode;
|
||||
module.exports.encode = encode;
|
||||
208
node_modules/openid-client/lib/helpers/client.js
generated
vendored
Normal file
208
node_modules/openid-client/lib/helpers/client.js
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
const jose = require('jose');
|
||||
|
||||
const { RPError } = require('../errors');
|
||||
|
||||
const { assertIssuerConfiguration } = require('./assert');
|
||||
const { random } = require('./generators');
|
||||
const now = require('./unix_timestamp');
|
||||
const request = require('./request');
|
||||
const { keystores } = require('./weak_cache');
|
||||
const merge = require('./merge');
|
||||
|
||||
// TODO: in v6.x additionally encode the `- _ . ! ~ * ' ( )` characters
|
||||
// https://github.com/panva/node-openid-client/commit/5a2ea80ef5e59ec0c03dbd97d82f551e24a9d348
|
||||
const formUrlEncode = (value) => encodeURIComponent(value).replace(/%20/g, '+');
|
||||
|
||||
async function clientAssertion(endpoint, payload) {
|
||||
let alg = this[`${endpoint}_endpoint_auth_signing_alg`];
|
||||
if (!alg) {
|
||||
assertIssuerConfiguration(
|
||||
this.issuer,
|
||||
`${endpoint}_endpoint_auth_signing_alg_values_supported`,
|
||||
);
|
||||
}
|
||||
|
||||
if (this[`${endpoint}_endpoint_auth_method`] === 'client_secret_jwt') {
|
||||
if (!alg) {
|
||||
const supported = this.issuer[`${endpoint}_endpoint_auth_signing_alg_values_supported`];
|
||||
alg =
|
||||
Array.isArray(supported) && supported.find((signAlg) => /^HS(?:256|384|512)/.test(signAlg));
|
||||
}
|
||||
|
||||
if (!alg) {
|
||||
throw new RPError(
|
||||
`failed to determine a JWS Algorithm to use for ${
|
||||
this[`${endpoint}_endpoint_auth_method`]
|
||||
} Client Assertion`,
|
||||
);
|
||||
}
|
||||
|
||||
return new jose.CompactSign(Buffer.from(JSON.stringify(payload)))
|
||||
.setProtectedHeader({ alg })
|
||||
.sign(this.secretForAlg(alg));
|
||||
}
|
||||
|
||||
const keystore = await keystores.get(this);
|
||||
|
||||
if (!keystore) {
|
||||
throw new TypeError('no client jwks provided for signing a client assertion with');
|
||||
}
|
||||
|
||||
if (!alg) {
|
||||
const supported = this.issuer[`${endpoint}_endpoint_auth_signing_alg_values_supported`];
|
||||
alg =
|
||||
Array.isArray(supported) &&
|
||||
supported.find((signAlg) => keystore.get({ alg: signAlg, use: 'sig' }));
|
||||
}
|
||||
|
||||
if (!alg) {
|
||||
throw new RPError(
|
||||
`failed to determine a JWS Algorithm to use for ${
|
||||
this[`${endpoint}_endpoint_auth_method`]
|
||||
} Client Assertion`,
|
||||
);
|
||||
}
|
||||
|
||||
const key = keystore.get({ alg, use: 'sig' });
|
||||
if (!key) {
|
||||
throw new RPError(
|
||||
`no key found in client jwks to sign a client assertion with using alg ${alg}`,
|
||||
);
|
||||
}
|
||||
|
||||
return new jose.CompactSign(Buffer.from(JSON.stringify(payload)))
|
||||
.setProtectedHeader({ alg, kid: key.jwk && key.jwk.kid })
|
||||
.sign(await key.keyObject(alg));
|
||||
}
|
||||
|
||||
async function authFor(endpoint, { clientAssertionPayload } = {}) {
|
||||
const authMethod = this[`${endpoint}_endpoint_auth_method`];
|
||||
switch (authMethod) {
|
||||
case 'self_signed_tls_client_auth':
|
||||
case 'tls_client_auth':
|
||||
case 'none':
|
||||
return { form: { client_id: this.client_id } };
|
||||
case 'client_secret_post':
|
||||
if (typeof this.client_secret !== 'string') {
|
||||
throw new TypeError(
|
||||
'client_secret_post client authentication method requires a client_secret',
|
||||
);
|
||||
}
|
||||
return { form: { client_id: this.client_id, client_secret: this.client_secret } };
|
||||
case 'private_key_jwt':
|
||||
case 'client_secret_jwt': {
|
||||
const timestamp = now();
|
||||
|
||||
const assertion = await clientAssertion.call(this, endpoint, {
|
||||
iat: timestamp,
|
||||
exp: timestamp + 60,
|
||||
jti: random(),
|
||||
iss: this.client_id,
|
||||
sub: this.client_id,
|
||||
aud: this.issuer.issuer,
|
||||
...clientAssertionPayload,
|
||||
});
|
||||
|
||||
return {
|
||||
form: {
|
||||
client_id: this.client_id,
|
||||
client_assertion: assertion,
|
||||
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
|
||||
},
|
||||
};
|
||||
}
|
||||
case 'client_secret_basic': {
|
||||
// This is correct behaviour, see https://tools.ietf.org/html/rfc6749#section-2.3.1 and the
|
||||
// related appendix. (also https://github.com/panva/node-openid-client/pull/91)
|
||||
// > The client identifier is encoded using the
|
||||
// > "application/x-www-form-urlencoded" encoding algorithm per
|
||||
// > Appendix B, and the encoded value is used as the username; the client
|
||||
// > password is encoded using the same algorithm and used as the
|
||||
// > password.
|
||||
if (typeof this.client_secret !== 'string') {
|
||||
throw new TypeError(
|
||||
'client_secret_basic client authentication method requires a client_secret',
|
||||
);
|
||||
}
|
||||
const encoded = `${formUrlEncode(this.client_id)}:${formUrlEncode(this.client_secret)}`;
|
||||
const value = Buffer.from(encoded).toString('base64');
|
||||
return { headers: { Authorization: `Basic ${value}` } };
|
||||
}
|
||||
default: {
|
||||
throw new TypeError(`missing, or unsupported, ${endpoint}_endpoint_auth_method`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resolveResponseType() {
|
||||
const { length, 0: value } = this.response_types;
|
||||
|
||||
if (length === 1) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function resolveRedirectUri() {
|
||||
const { length, 0: value } = this.redirect_uris || [];
|
||||
|
||||
if (length === 1) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function authenticatedPost(
|
||||
endpoint,
|
||||
opts,
|
||||
{ clientAssertionPayload, endpointAuthMethod = endpoint, DPoP } = {},
|
||||
) {
|
||||
const auth = await authFor.call(this, endpointAuthMethod, { clientAssertionPayload });
|
||||
const requestOpts = merge(opts, auth);
|
||||
|
||||
const mTLS =
|
||||
this[`${endpointAuthMethod}_endpoint_auth_method`].includes('tls_client_auth') ||
|
||||
(endpoint === 'token' && this.tls_client_certificate_bound_access_tokens);
|
||||
|
||||
let targetUrl;
|
||||
if (mTLS && this.issuer.mtls_endpoint_aliases) {
|
||||
targetUrl = this.issuer.mtls_endpoint_aliases[`${endpoint}_endpoint`];
|
||||
}
|
||||
|
||||
targetUrl = targetUrl || this.issuer[`${endpoint}_endpoint`];
|
||||
|
||||
if ('form' in requestOpts) {
|
||||
for (const [key, value] of Object.entries(requestOpts.form)) {
|
||||
if (typeof value === 'undefined') {
|
||||
delete requestOpts.form[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return request.call(
|
||||
this,
|
||||
{
|
||||
...requestOpts,
|
||||
method: 'POST',
|
||||
url: targetUrl,
|
||||
headers: {
|
||||
...(endpoint !== 'revocation'
|
||||
? {
|
||||
Accept: 'application/json',
|
||||
}
|
||||
: undefined),
|
||||
...requestOpts.headers,
|
||||
},
|
||||
},
|
||||
{ mTLS, DPoP },
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
resolveResponseType,
|
||||
resolveRedirectUri,
|
||||
authFor,
|
||||
authenticatedPost,
|
||||
};
|
||||
7
node_modules/openid-client/lib/helpers/consts.js
generated
vendored
Normal file
7
node_modules/openid-client/lib/helpers/consts.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
const HTTP_OPTIONS = Symbol();
|
||||
const CLOCK_TOLERANCE = Symbol();
|
||||
|
||||
module.exports = {
|
||||
CLOCK_TOLERANCE,
|
||||
HTTP_OPTIONS,
|
||||
};
|
||||
27
node_modules/openid-client/lib/helpers/decode_jwt.js
generated
vendored
Normal file
27
node_modules/openid-client/lib/helpers/decode_jwt.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
const base64url = require('./base64url');
|
||||
|
||||
module.exports = (token) => {
|
||||
if (typeof token !== 'string' || !token) {
|
||||
throw new TypeError('JWT must be a string');
|
||||
}
|
||||
|
||||
const { 0: header, 1: payload, 2: signature, length } = token.split('.');
|
||||
|
||||
if (length === 5) {
|
||||
throw new TypeError('encrypted JWTs cannot be decoded');
|
||||
}
|
||||
|
||||
if (length !== 3) {
|
||||
throw new Error('JWTs must have three components');
|
||||
}
|
||||
|
||||
try {
|
||||
return {
|
||||
header: JSON.parse(base64url.decode(header)),
|
||||
payload: JSON.parse(base64url.decode(payload)),
|
||||
signature,
|
||||
};
|
||||
} catch (err) {
|
||||
throw new Error('JWT is malformed');
|
||||
}
|
||||
};
|
||||
1
node_modules/openid-client/lib/helpers/deep_clone.js
generated
vendored
Normal file
1
node_modules/openid-client/lib/helpers/deep_clone.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = globalThis.structuredClone || ((obj) => JSON.parse(JSON.stringify(obj)));
|
||||
27
node_modules/openid-client/lib/helpers/defaults.js
generated
vendored
Normal file
27
node_modules/openid-client/lib/helpers/defaults.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
const isPlainObject = require('./is_plain_object');
|
||||
|
||||
function defaults(deep, target, ...sources) {
|
||||
for (const source of sources) {
|
||||
if (!isPlainObject(source)) {
|
||||
continue;
|
||||
}
|
||||
for (const [key, value] of Object.entries(source)) {
|
||||
/* istanbul ignore if */
|
||||
if (key === '__proto__' || key === 'constructor') {
|
||||
continue;
|
||||
}
|
||||
if (typeof target[key] === 'undefined' && typeof value !== 'undefined') {
|
||||
target[key] = value;
|
||||
}
|
||||
|
||||
if (deep && isPlainObject(target[key]) && isPlainObject(value)) {
|
||||
defaults(true, target[key], value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
module.exports = defaults.bind(undefined, false);
|
||||
module.exports.deep = defaults.bind(undefined, true);
|
||||
14
node_modules/openid-client/lib/helpers/generators.js
generated
vendored
Normal file
14
node_modules/openid-client/lib/helpers/generators.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
const { createHash, randomBytes } = require('crypto');
|
||||
|
||||
const base64url = require('./base64url');
|
||||
|
||||
const random = (bytes = 32) => base64url.encode(randomBytes(bytes));
|
||||
|
||||
module.exports = {
|
||||
random,
|
||||
state: random,
|
||||
nonce: random,
|
||||
codeVerifier: random,
|
||||
codeChallenge: (codeVerifier) =>
|
||||
base64url.encode(createHash('sha256').update(codeVerifier).digest()),
|
||||
};
|
||||
4
node_modules/openid-client/lib/helpers/is_key_object.js
generated
vendored
Normal file
4
node_modules/openid-client/lib/helpers/is_key_object.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
const util = require('util');
|
||||
const crypto = require('crypto');
|
||||
|
||||
module.exports = util.types.isKeyObject || ((obj) => obj && obj instanceof crypto.KeyObject);
|
||||
1
node_modules/openid-client/lib/helpers/is_plain_object.js
generated
vendored
Normal file
1
node_modules/openid-client/lib/helpers/is_plain_object.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = (a) => !!a && a.constructor === Object;
|
||||
111
node_modules/openid-client/lib/helpers/issuer.js
generated
vendored
Normal file
111
node_modules/openid-client/lib/helpers/issuer.js
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
const objectHash = require('object-hash');
|
||||
const LRU = require('lru-cache');
|
||||
|
||||
const { RPError } = require('../errors');
|
||||
|
||||
const { assertIssuerConfiguration } = require('./assert');
|
||||
const KeyStore = require('./keystore');
|
||||
const { keystores } = require('./weak_cache');
|
||||
const processResponse = require('./process_response');
|
||||
const request = require('./request');
|
||||
|
||||
const inFlight = new WeakMap();
|
||||
const caches = new WeakMap();
|
||||
const lrus = (ctx) => {
|
||||
if (!caches.has(ctx)) {
|
||||
caches.set(ctx, new LRU({ max: 100 }));
|
||||
}
|
||||
return caches.get(ctx);
|
||||
};
|
||||
|
||||
async function getKeyStore(reload = false) {
|
||||
assertIssuerConfiguration(this, 'jwks_uri');
|
||||
|
||||
const keystore = keystores.get(this);
|
||||
const cache = lrus(this);
|
||||
|
||||
if (reload || !keystore) {
|
||||
if (inFlight.has(this)) {
|
||||
return inFlight.get(this);
|
||||
}
|
||||
cache.reset();
|
||||
inFlight.set(
|
||||
this,
|
||||
(async () => {
|
||||
const response = await request
|
||||
.call(this, {
|
||||
method: 'GET',
|
||||
responseType: 'json',
|
||||
url: this.jwks_uri,
|
||||
headers: {
|
||||
Accept: 'application/json, application/jwk-set+json',
|
||||
},
|
||||
})
|
||||
.finally(() => {
|
||||
inFlight.delete(this);
|
||||
});
|
||||
const jwks = processResponse(response);
|
||||
|
||||
const joseKeyStore = KeyStore.fromJWKS(jwks, { onlyPublic: true });
|
||||
cache.set('throttle', true, 60 * 1000);
|
||||
keystores.set(this, joseKeyStore);
|
||||
|
||||
return joseKeyStore;
|
||||
})(),
|
||||
);
|
||||
|
||||
return inFlight.get(this);
|
||||
}
|
||||
|
||||
return keystore;
|
||||
}
|
||||
|
||||
async function queryKeyStore({ kid, kty, alg, use }, { allowMulti = false } = {}) {
|
||||
const cache = lrus(this);
|
||||
|
||||
const def = {
|
||||
kid,
|
||||
kty,
|
||||
alg,
|
||||
use,
|
||||
};
|
||||
|
||||
const defHash = objectHash(def, {
|
||||
algorithm: 'sha256',
|
||||
ignoreUnknown: true,
|
||||
unorderedArrays: true,
|
||||
unorderedSets: true,
|
||||
respectType: false,
|
||||
});
|
||||
|
||||
// refresh keystore on every unknown key but also only upto once every minute
|
||||
const freshJwksUri = cache.get(defHash) || cache.get('throttle');
|
||||
|
||||
const keystore = await getKeyStore.call(this, !freshJwksUri);
|
||||
const keys = keystore.all(def);
|
||||
|
||||
delete def.use;
|
||||
if (keys.length === 0) {
|
||||
throw new RPError({
|
||||
printf: ["no valid key found in issuer's jwks_uri for key parameters %j", def],
|
||||
jwks: keystore,
|
||||
});
|
||||
}
|
||||
|
||||
if (!allowMulti && keys.length > 1 && !kid) {
|
||||
throw new RPError({
|
||||
printf: [
|
||||
"multiple matching keys found in issuer's jwks_uri for key parameters %j, kid must be provided in this case",
|
||||
def,
|
||||
],
|
||||
jwks: keystore,
|
||||
});
|
||||
}
|
||||
|
||||
cache.set(defHash, true);
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
module.exports.queryKeyStore = queryKeyStore;
|
||||
module.exports.keystore = getKeyStore;
|
||||
298
node_modules/openid-client/lib/helpers/keystore.js
generated
vendored
Normal file
298
node_modules/openid-client/lib/helpers/keystore.js
generated
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
const jose = require('jose');
|
||||
|
||||
const clone = require('./deep_clone');
|
||||
const isPlainObject = require('./is_plain_object');
|
||||
|
||||
const internal = Symbol();
|
||||
|
||||
const keyscore = (key, { alg, use }) => {
|
||||
let score = 0;
|
||||
|
||||
if (alg && key.alg) {
|
||||
score++;
|
||||
}
|
||||
|
||||
if (use && key.use) {
|
||||
score++;
|
||||
}
|
||||
|
||||
return score;
|
||||
};
|
||||
|
||||
function getKtyFromAlg(alg) {
|
||||
switch (typeof alg === 'string' && alg.slice(0, 2)) {
|
||||
case 'RS':
|
||||
case 'PS':
|
||||
return 'RSA';
|
||||
case 'ES':
|
||||
return 'EC';
|
||||
case 'Ed':
|
||||
return 'OKP';
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function getAlgorithms(use, alg, kty, crv) {
|
||||
// Ed25519, Ed448, and secp256k1 always have "alg"
|
||||
// OKP always has "use"
|
||||
if (alg) {
|
||||
return new Set([alg]);
|
||||
}
|
||||
|
||||
switch (kty) {
|
||||
case 'EC': {
|
||||
let algs = [];
|
||||
|
||||
if (use === 'enc' || use === undefined) {
|
||||
algs = algs.concat(['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']);
|
||||
}
|
||||
|
||||
if (use === 'sig' || use === undefined) {
|
||||
switch (crv) {
|
||||
case 'P-256':
|
||||
case 'P-384':
|
||||
algs = algs.concat([`ES${crv.slice(-3)}`]);
|
||||
break;
|
||||
case 'P-521':
|
||||
algs = algs.concat(['ES512']);
|
||||
break;
|
||||
case 'secp256k1':
|
||||
if (jose.cryptoRuntime === 'node:crypto') {
|
||||
algs = algs.concat(['ES256K']);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new Set(algs);
|
||||
}
|
||||
case 'OKP': {
|
||||
return new Set(['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']);
|
||||
}
|
||||
case 'RSA': {
|
||||
let algs = [];
|
||||
|
||||
if (use === 'enc' || use === undefined) {
|
||||
algs = algs.concat(['RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512']);
|
||||
if (jose.cryptoRuntime === 'node:crypto') {
|
||||
algs = algs.concat(['RSA1_5']);
|
||||
}
|
||||
}
|
||||
|
||||
if (use === 'sig' || use === undefined) {
|
||||
algs = algs.concat(['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512']);
|
||||
}
|
||||
|
||||
return new Set(algs);
|
||||
}
|
||||
default:
|
||||
throw new Error('unreachable');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = class KeyStore {
|
||||
#keys;
|
||||
|
||||
constructor(i, keys) {
|
||||
if (i !== internal) throw new Error('invalid constructor call');
|
||||
this.#keys = keys;
|
||||
}
|
||||
|
||||
toJWKS() {
|
||||
return {
|
||||
keys: this.map(({ jwk: { d, p, q, dp, dq, qi, ...jwk } }) => jwk),
|
||||
};
|
||||
}
|
||||
|
||||
all({ alg, kid, use } = {}) {
|
||||
if (!use || !alg) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
const kty = getKtyFromAlg(alg);
|
||||
|
||||
const search = { alg, use };
|
||||
return this.filter((key) => {
|
||||
let candidate = true;
|
||||
|
||||
if (candidate && kty !== undefined && key.jwk.kty !== kty) {
|
||||
candidate = false;
|
||||
}
|
||||
|
||||
if (candidate && kid !== undefined && key.jwk.kid !== kid) {
|
||||
candidate = false;
|
||||
}
|
||||
|
||||
if (candidate && use !== undefined && key.jwk.use !== undefined && key.jwk.use !== use) {
|
||||
candidate = false;
|
||||
}
|
||||
|
||||
if (candidate && key.jwk.alg && key.jwk.alg !== alg) {
|
||||
candidate = false;
|
||||
} else if (!key.algorithms.has(alg)) {
|
||||
candidate = false;
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}).sort((first, second) => keyscore(second, search) - keyscore(first, search));
|
||||
}
|
||||
|
||||
get(...args) {
|
||||
return this.all(...args)[0];
|
||||
}
|
||||
|
||||
static async fromJWKS(jwks, { onlyPublic = false, onlyPrivate = false } = {}) {
|
||||
if (
|
||||
!isPlainObject(jwks) ||
|
||||
!Array.isArray(jwks.keys) ||
|
||||
jwks.keys.some((k) => !isPlainObject(k) || !('kty' in k))
|
||||
) {
|
||||
throw new TypeError('jwks must be a JSON Web Key Set formatted object');
|
||||
}
|
||||
|
||||
const keys = [];
|
||||
|
||||
for (let jwk of jwks.keys) {
|
||||
jwk = clone(jwk);
|
||||
const { kty, kid, crv } = jwk;
|
||||
|
||||
let { alg, use } = jwk;
|
||||
|
||||
if (typeof kty !== 'string' || !kty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (use !== undefined && use !== 'sig' && use !== 'enc') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof alg !== 'string' && alg !== undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof kid !== 'string' && kid !== undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (kty === 'EC' && use === 'sig') {
|
||||
switch (crv) {
|
||||
case 'P-256':
|
||||
alg = 'ES256';
|
||||
break;
|
||||
case 'P-384':
|
||||
alg = 'ES384';
|
||||
break;
|
||||
case 'P-521':
|
||||
alg = 'ES512';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (crv === 'secp256k1') {
|
||||
use = 'sig';
|
||||
alg = 'ES256K';
|
||||
}
|
||||
|
||||
if (kty === 'OKP') {
|
||||
switch (crv) {
|
||||
case 'Ed25519':
|
||||
case 'Ed448':
|
||||
use = 'sig';
|
||||
alg = 'EdDSA';
|
||||
break;
|
||||
case 'X25519':
|
||||
case 'X448':
|
||||
use = 'enc';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (alg && !use) {
|
||||
switch (true) {
|
||||
case alg.startsWith('ECDH'):
|
||||
use = 'enc';
|
||||
break;
|
||||
case alg.startsWith('RSA'):
|
||||
use = 'enc';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (onlyPrivate && (jwk.kty === 'oct' || !jwk.d)) {
|
||||
throw new Error('jwks must only contain private keys');
|
||||
}
|
||||
|
||||
if (onlyPublic && (jwk.d || jwk.k)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
keys.push({
|
||||
jwk: { ...jwk, alg, use },
|
||||
async keyObject(alg) {
|
||||
if (this[alg]) {
|
||||
return this[alg];
|
||||
}
|
||||
|
||||
const keyObject = await jose.importJWK(this.jwk, alg);
|
||||
this[alg] = keyObject;
|
||||
return keyObject;
|
||||
},
|
||||
get algorithms() {
|
||||
Object.defineProperty(this, 'algorithms', {
|
||||
value: getAlgorithms(this.jwk.use, this.jwk.alg, this.jwk.kty, this.jwk.crv),
|
||||
enumerable: true,
|
||||
configurable: false,
|
||||
});
|
||||
return this.algorithms;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return new this(internal, keys);
|
||||
}
|
||||
|
||||
filter(...args) {
|
||||
return this.#keys.filter(...args);
|
||||
}
|
||||
|
||||
find(...args) {
|
||||
return this.#keys.find(...args);
|
||||
}
|
||||
|
||||
every(...args) {
|
||||
return this.#keys.every(...args);
|
||||
}
|
||||
|
||||
some(...args) {
|
||||
return this.#keys.some(...args);
|
||||
}
|
||||
|
||||
map(...args) {
|
||||
return this.#keys.map(...args);
|
||||
}
|
||||
|
||||
forEach(...args) {
|
||||
return this.#keys.forEach(...args);
|
||||
}
|
||||
|
||||
reduce(...args) {
|
||||
return this.#keys.reduce(...args);
|
||||
}
|
||||
|
||||
sort(...args) {
|
||||
return this.#keys.sort(...args);
|
||||
}
|
||||
|
||||
*[Symbol.iterator]() {
|
||||
for (const key of this.#keys) {
|
||||
yield key;
|
||||
}
|
||||
}
|
||||
};
|
||||
24
node_modules/openid-client/lib/helpers/merge.js
generated
vendored
Normal file
24
node_modules/openid-client/lib/helpers/merge.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
const isPlainObject = require('./is_plain_object');
|
||||
|
||||
function merge(target, ...sources) {
|
||||
for (const source of sources) {
|
||||
if (!isPlainObject(source)) {
|
||||
continue;
|
||||
}
|
||||
for (const [key, value] of Object.entries(source)) {
|
||||
/* istanbul ignore if */
|
||||
if (key === '__proto__' || key === 'constructor') {
|
||||
continue;
|
||||
}
|
||||
if (isPlainObject(target[key]) && isPlainObject(value)) {
|
||||
target[key] = merge(target[key], value);
|
||||
} else if (typeof value !== 'undefined') {
|
||||
target[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
module.exports = merge;
|
||||
9
node_modules/openid-client/lib/helpers/pick.js
generated
vendored
Normal file
9
node_modules/openid-client/lib/helpers/pick.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module.exports = function pick(object, ...paths) {
|
||||
const obj = {};
|
||||
for (const path of paths) {
|
||||
if (object[path] !== undefined) {
|
||||
obj[path] = object[path];
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
71
node_modules/openid-client/lib/helpers/process_response.js
generated
vendored
Normal file
71
node_modules/openid-client/lib/helpers/process_response.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
const { STATUS_CODES } = require('http');
|
||||
const { format } = require('util');
|
||||
|
||||
const { OPError } = require('../errors');
|
||||
const parseWwwAuthenticate = require('./www_authenticate_parser');
|
||||
|
||||
const throwAuthenticateErrors = (response) => {
|
||||
const params = parseWwwAuthenticate(response.headers['www-authenticate']);
|
||||
|
||||
if (params.error) {
|
||||
throw new OPError(params, response);
|
||||
}
|
||||
};
|
||||
|
||||
const isStandardBodyError = (response) => {
|
||||
let result = false;
|
||||
try {
|
||||
let jsonbody;
|
||||
if (typeof response.body !== 'object' || Buffer.isBuffer(response.body)) {
|
||||
jsonbody = JSON.parse(response.body);
|
||||
} else {
|
||||
jsonbody = response.body;
|
||||
}
|
||||
result = typeof jsonbody.error === 'string' && jsonbody.error.length;
|
||||
if (result) Object.defineProperty(response, 'body', { value: jsonbody, configurable: true });
|
||||
} catch (err) {}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
function processResponse(response, { statusCode = 200, body = true, bearer = false } = {}) {
|
||||
if (response.statusCode !== statusCode) {
|
||||
if (bearer) {
|
||||
throwAuthenticateErrors(response);
|
||||
}
|
||||
|
||||
if (isStandardBodyError(response)) {
|
||||
throw new OPError(response.body, response);
|
||||
}
|
||||
|
||||
throw new OPError(
|
||||
{
|
||||
error: format(
|
||||
'expected %i %s, got: %i %s',
|
||||
statusCode,
|
||||
STATUS_CODES[statusCode],
|
||||
response.statusCode,
|
||||
STATUS_CODES[response.statusCode],
|
||||
),
|
||||
},
|
||||
response,
|
||||
);
|
||||
}
|
||||
|
||||
if (body && !response.body) {
|
||||
throw new OPError(
|
||||
{
|
||||
error: format(
|
||||
'expected %i %s with body but no body was returned',
|
||||
statusCode,
|
||||
STATUS_CODES[statusCode],
|
||||
),
|
||||
},
|
||||
response,
|
||||
);
|
||||
}
|
||||
|
||||
return response.body;
|
||||
}
|
||||
|
||||
module.exports = processResponse;
|
||||
200
node_modules/openid-client/lib/helpers/request.js
generated
vendored
Normal file
200
node_modules/openid-client/lib/helpers/request.js
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
const assert = require('assert');
|
||||
const querystring = require('querystring');
|
||||
const http = require('http');
|
||||
const https = require('https');
|
||||
const { once } = require('events');
|
||||
const { URL } = require('url');
|
||||
|
||||
const LRU = require('lru-cache');
|
||||
|
||||
const pkg = require('../../package.json');
|
||||
const { RPError } = require('../errors');
|
||||
|
||||
const pick = require('./pick');
|
||||
const { deep: defaultsDeep } = require('./defaults');
|
||||
const { HTTP_OPTIONS } = require('./consts');
|
||||
|
||||
let DEFAULT_HTTP_OPTIONS;
|
||||
const NQCHAR = /^[\x21\x23-\x5B\x5D-\x7E]+$/;
|
||||
|
||||
const allowed = [
|
||||
'agent',
|
||||
'ca',
|
||||
'cert',
|
||||
'crl',
|
||||
'headers',
|
||||
'key',
|
||||
'lookup',
|
||||
'passphrase',
|
||||
'pfx',
|
||||
'timeout',
|
||||
];
|
||||
|
||||
const setDefaults = (props, options) => {
|
||||
DEFAULT_HTTP_OPTIONS = defaultsDeep(
|
||||
{},
|
||||
props.length ? pick(options, ...props) : options,
|
||||
DEFAULT_HTTP_OPTIONS,
|
||||
);
|
||||
};
|
||||
|
||||
setDefaults([], {
|
||||
headers: {
|
||||
'User-Agent': `${pkg.name}/${pkg.version} (${pkg.homepage})`,
|
||||
'Accept-Encoding': 'identity',
|
||||
},
|
||||
timeout: 3500,
|
||||
});
|
||||
|
||||
function send(req, body, contentType) {
|
||||
if (contentType) {
|
||||
req.removeHeader('content-type');
|
||||
req.setHeader('content-type', contentType);
|
||||
}
|
||||
if (body) {
|
||||
req.removeHeader('content-length');
|
||||
req.setHeader('content-length', Buffer.byteLength(body));
|
||||
req.write(body);
|
||||
}
|
||||
req.end();
|
||||
}
|
||||
|
||||
const nonces = new LRU({ max: 100 });
|
||||
|
||||
module.exports = async function request(options, { accessToken, mTLS = false, DPoP } = {}) {
|
||||
let url;
|
||||
try {
|
||||
url = new URL(options.url);
|
||||
delete options.url;
|
||||
assert(/^(https?:)$/.test(url.protocol));
|
||||
} catch (err) {
|
||||
throw new TypeError('only valid absolute URLs can be requested');
|
||||
}
|
||||
const optsFn = this[HTTP_OPTIONS];
|
||||
let opts = options;
|
||||
|
||||
const nonceKey = `${url.origin}${url.pathname}`;
|
||||
if (DPoP && 'dpopProof' in this) {
|
||||
opts.headers = opts.headers || {};
|
||||
opts.headers.DPoP = await this.dpopProof(
|
||||
{
|
||||
htu: `${url.origin}${url.pathname}`,
|
||||
htm: options.method || 'GET',
|
||||
nonce: nonces.get(nonceKey),
|
||||
},
|
||||
DPoP,
|
||||
accessToken,
|
||||
);
|
||||
}
|
||||
|
||||
let userOptions;
|
||||
if (optsFn) {
|
||||
userOptions = pick(
|
||||
optsFn.call(this, url, defaultsDeep({}, opts, DEFAULT_HTTP_OPTIONS)),
|
||||
...allowed,
|
||||
);
|
||||
}
|
||||
opts = defaultsDeep({}, userOptions, opts, DEFAULT_HTTP_OPTIONS);
|
||||
|
||||
if (mTLS && !opts.pfx && !(opts.key && opts.cert)) {
|
||||
throw new TypeError('mutual-TLS certificate and key not set');
|
||||
}
|
||||
|
||||
if (opts.searchParams) {
|
||||
for (const [key, value] of Object.entries(opts.searchParams)) {
|
||||
url.searchParams.delete(key);
|
||||
url.searchParams.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
let responseType;
|
||||
let form;
|
||||
let json;
|
||||
let body;
|
||||
({ form, responseType, json, body, ...opts } = opts);
|
||||
|
||||
for (const [key, value] of Object.entries(opts.headers || {})) {
|
||||
if (value === undefined) {
|
||||
delete opts.headers[key];
|
||||
}
|
||||
}
|
||||
|
||||
let response;
|
||||
const req = (url.protocol === 'https:' ? https.request : http.request)(url.href, opts);
|
||||
return (async () => {
|
||||
if (json) {
|
||||
send(req, JSON.stringify(json), 'application/json');
|
||||
} else if (form) {
|
||||
send(req, querystring.stringify(form), 'application/x-www-form-urlencoded');
|
||||
} else if (body) {
|
||||
send(req, body);
|
||||
} else {
|
||||
send(req);
|
||||
}
|
||||
|
||||
[response] = await Promise.race([once(req, 'response'), once(req, 'timeout')]);
|
||||
|
||||
// timeout reached
|
||||
if (!response) {
|
||||
req.destroy();
|
||||
throw new RPError(`outgoing request timed out after ${opts.timeout}ms`);
|
||||
}
|
||||
|
||||
const parts = [];
|
||||
|
||||
for await (const part of response) {
|
||||
parts.push(part);
|
||||
}
|
||||
|
||||
if (parts.length) {
|
||||
switch (responseType) {
|
||||
case 'json': {
|
||||
Object.defineProperty(response, 'body', {
|
||||
get() {
|
||||
let value = Buffer.concat(parts);
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
} catch (err) {
|
||||
Object.defineProperty(err, 'response', { value: response });
|
||||
throw err;
|
||||
} finally {
|
||||
Object.defineProperty(response, 'body', { value, configurable: true });
|
||||
}
|
||||
return value;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case undefined:
|
||||
case 'buffer': {
|
||||
Object.defineProperty(response, 'body', {
|
||||
get() {
|
||||
const value = Buffer.concat(parts);
|
||||
Object.defineProperty(response, 'body', { value, configurable: true });
|
||||
return value;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new TypeError('unsupported responseType request option');
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
})()
|
||||
.catch((err) => {
|
||||
if (response) Object.defineProperty(err, 'response', { value: response });
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
const dpopNonce = response && response.headers['dpop-nonce'];
|
||||
if (dpopNonce && NQCHAR.test(dpopNonce)) {
|
||||
nonces.set(nonceKey, dpopNonce);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.setDefaults = setDefaults.bind(undefined, allowed);
|
||||
1
node_modules/openid-client/lib/helpers/unix_timestamp.js
generated
vendored
Normal file
1
node_modules/openid-client/lib/helpers/unix_timestamp.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = () => Math.floor(Date.now() / 1000);
|
||||
1
node_modules/openid-client/lib/helpers/weak_cache.js
generated
vendored
Normal file
1
node_modules/openid-client/lib/helpers/weak_cache.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports.keystores = new WeakMap();
|
||||
71
node_modules/openid-client/lib/helpers/webfinger_normalize.js
generated
vendored
Normal file
71
node_modules/openid-client/lib/helpers/webfinger_normalize.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
// Credit: https://github.com/rohe/pyoidc/blob/master/src/oic/utils/webfinger.py
|
||||
|
||||
// -- Normalization --
|
||||
// A string of any other type is interpreted as a URI either the form of scheme
|
||||
// "://" authority path-abempty [ "?" query ] [ "#" fragment ] or authority
|
||||
// path-abempty [ "?" query ] [ "#" fragment ] per RFC 3986 [RFC3986] and is
|
||||
// normalized according to the following rules:
|
||||
//
|
||||
// If the user input Identifier does not have an RFC 3986 [RFC3986] scheme
|
||||
// portion, the string is interpreted as [userinfo "@"] host [":" port]
|
||||
// path-abempty [ "?" query ] [ "#" fragment ] per RFC 3986 [RFC3986].
|
||||
// If the userinfo component is present and all of the path component, query
|
||||
// component, and port component are empty, the acct scheme is assumed. In this
|
||||
// case, the normalized URI is formed by prefixing acct: to the string as the
|
||||
// scheme. Per the 'acct' URI Scheme [I‑D.ietf‑appsawg‑acct‑uri], if there is an
|
||||
// at-sign character ('@') in the userinfo component, it needs to be
|
||||
// percent-encoded as described in RFC 3986 [RFC3986].
|
||||
// For all other inputs without a scheme portion, the https scheme is assumed,
|
||||
// and the normalized URI is formed by prefixing https:// to the string as the
|
||||
// scheme.
|
||||
// If the resulting URI contains a fragment portion, it MUST be stripped off
|
||||
// together with the fragment delimiter character "#".
|
||||
// The WebFinger [I‑D.ietf‑appsawg‑webfinger] Resource in this case is the
|
||||
// resulting URI, and the WebFinger Host is the authority component.
|
||||
//
|
||||
// Note: Since the definition of authority in RFC 3986 [RFC3986] is
|
||||
// [ userinfo "@" ] host [ ":" port ], it is legal to have a user input
|
||||
// identifier like userinfo@host:port, e.g., alice@example.com:8080.
|
||||
|
||||
const PORT = /^\d+$/;
|
||||
|
||||
function hasScheme(input) {
|
||||
if (input.includes('://')) return true;
|
||||
|
||||
const authority = input.replace(/(\/|\?)/g, '#').split('#')[0];
|
||||
if (authority.includes(':')) {
|
||||
const index = authority.indexOf(':');
|
||||
const hostOrPort = authority.slice(index + 1);
|
||||
if (!PORT.test(hostOrPort)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function acctSchemeAssumed(input) {
|
||||
if (!input.includes('@')) return false;
|
||||
const parts = input.split('@');
|
||||
const host = parts[parts.length - 1];
|
||||
return !(host.includes(':') || host.includes('/') || host.includes('?'));
|
||||
}
|
||||
|
||||
function normalize(input) {
|
||||
if (typeof input !== 'string') {
|
||||
throw new TypeError('input must be a string');
|
||||
}
|
||||
|
||||
let output;
|
||||
if (hasScheme(input)) {
|
||||
output = input;
|
||||
} else if (acctSchemeAssumed(input)) {
|
||||
output = `acct:${input}`;
|
||||
} else {
|
||||
output = `https://${input}`;
|
||||
}
|
||||
|
||||
return output.split('#')[0];
|
||||
}
|
||||
|
||||
module.exports = normalize;
|
||||
14
node_modules/openid-client/lib/helpers/www_authenticate_parser.js
generated
vendored
Normal file
14
node_modules/openid-client/lib/helpers/www_authenticate_parser.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
const REGEXP = /(\w+)=("[^"]*")/g;
|
||||
|
||||
module.exports = (wwwAuthenticate) => {
|
||||
const params = {};
|
||||
try {
|
||||
while (REGEXP.exec(wwwAuthenticate) !== null) {
|
||||
if (RegExp.$1 && RegExp.$2) {
|
||||
params[RegExp.$1] = RegExp.$2.slice(1, -1);
|
||||
}
|
||||
}
|
||||
} catch (err) {}
|
||||
|
||||
return params;
|
||||
};
|
||||
23
node_modules/openid-client/lib/index.js
generated
vendored
Normal file
23
node_modules/openid-client/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
const Issuer = require('./issuer');
|
||||
const { OPError, RPError } = require('./errors');
|
||||
const Strategy = require('./passport_strategy');
|
||||
const TokenSet = require('./token_set');
|
||||
const { CLOCK_TOLERANCE, HTTP_OPTIONS } = require('./helpers/consts');
|
||||
const generators = require('./helpers/generators');
|
||||
const { setDefaults } = require('./helpers/request');
|
||||
|
||||
module.exports = {
|
||||
Issuer,
|
||||
Strategy,
|
||||
TokenSet,
|
||||
errors: {
|
||||
OPError,
|
||||
RPError,
|
||||
},
|
||||
custom: {
|
||||
setHttpOptionsDefaults: setDefaults,
|
||||
http_options: HTTP_OPTIONS,
|
||||
clock_tolerance: CLOCK_TOLERANCE,
|
||||
},
|
||||
generators,
|
||||
};
|
||||
9
node_modules/openid-client/lib/index.mjs
generated
vendored
Normal file
9
node_modules/openid-client/lib/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import mod from './index.js';
|
||||
|
||||
export default mod;
|
||||
export const Issuer = mod.Issuer;
|
||||
export const Strategy = mod.Strategy;
|
||||
export const TokenSet = mod.TokenSet;
|
||||
export const errors = mod.errors;
|
||||
export const custom = mod.custom;
|
||||
export const generators = mod.generators;
|
||||
192
node_modules/openid-client/lib/issuer.js
generated
vendored
Normal file
192
node_modules/openid-client/lib/issuer.js
generated
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
const { inspect } = require('util');
|
||||
const url = require('url');
|
||||
|
||||
const { RPError } = require('./errors');
|
||||
const getClient = require('./client');
|
||||
const registry = require('./issuer_registry');
|
||||
const processResponse = require('./helpers/process_response');
|
||||
const webfingerNormalize = require('./helpers/webfinger_normalize');
|
||||
const request = require('./helpers/request');
|
||||
const clone = require('./helpers/deep_clone');
|
||||
const { keystore } = require('./helpers/issuer');
|
||||
|
||||
const AAD_MULTITENANT_DISCOVERY = [
|
||||
'https://login.microsoftonline.com/common/.well-known/openid-configuration',
|
||||
'https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration',
|
||||
'https://login.microsoftonline.com/organizations/v2.0/.well-known/openid-configuration',
|
||||
'https://login.microsoftonline.com/consumers/v2.0/.well-known/openid-configuration',
|
||||
];
|
||||
const AAD_MULTITENANT = Symbol();
|
||||
const ISSUER_DEFAULTS = {
|
||||
claim_types_supported: ['normal'],
|
||||
claims_parameter_supported: false,
|
||||
grant_types_supported: ['authorization_code', 'implicit'],
|
||||
request_parameter_supported: false,
|
||||
request_uri_parameter_supported: true,
|
||||
require_request_uri_registration: false,
|
||||
response_modes_supported: ['query', 'fragment'],
|
||||
token_endpoint_auth_methods_supported: ['client_secret_basic'],
|
||||
};
|
||||
|
||||
class Issuer {
|
||||
#metadata;
|
||||
constructor(meta = {}) {
|
||||
const aadIssValidation = meta[AAD_MULTITENANT];
|
||||
delete meta[AAD_MULTITENANT];
|
||||
['introspection', 'revocation'].forEach((endpoint) => {
|
||||
// if intro/revocation endpoint auth specific meta is missing use the token ones if they
|
||||
// are defined
|
||||
if (
|
||||
meta[`${endpoint}_endpoint`] &&
|
||||
meta[`${endpoint}_endpoint_auth_methods_supported`] === undefined &&
|
||||
meta[`${endpoint}_endpoint_auth_signing_alg_values_supported`] === undefined
|
||||
) {
|
||||
if (meta.token_endpoint_auth_methods_supported) {
|
||||
meta[`${endpoint}_endpoint_auth_methods_supported`] =
|
||||
meta.token_endpoint_auth_methods_supported;
|
||||
}
|
||||
if (meta.token_endpoint_auth_signing_alg_values_supported) {
|
||||
meta[`${endpoint}_endpoint_auth_signing_alg_values_supported`] =
|
||||
meta.token_endpoint_auth_signing_alg_values_supported;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.#metadata = new Map();
|
||||
|
||||
Object.entries(meta).forEach(([key, value]) => {
|
||||
this.#metadata.set(key, value);
|
||||
if (!this[key]) {
|
||||
Object.defineProperty(this, key, {
|
||||
get() {
|
||||
return this.#metadata.get(key);
|
||||
},
|
||||
enumerable: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
registry.set(this.issuer, this);
|
||||
|
||||
const Client = getClient(this, aadIssValidation);
|
||||
|
||||
Object.defineProperties(this, {
|
||||
Client: { value: Client, enumerable: true },
|
||||
FAPI1Client: { value: class FAPI1Client extends Client {}, enumerable: true },
|
||||
FAPI2Client: { value: class FAPI2Client extends Client {}, enumerable: true },
|
||||
});
|
||||
}
|
||||
|
||||
get metadata() {
|
||||
return clone(Object.fromEntries(this.#metadata.entries()));
|
||||
}
|
||||
|
||||
static async webfinger(input) {
|
||||
const resource = webfingerNormalize(input);
|
||||
const { host } = url.parse(resource);
|
||||
const webfingerUrl = `https://${host}/.well-known/webfinger`;
|
||||
|
||||
const response = await request.call(this, {
|
||||
method: 'GET',
|
||||
url: webfingerUrl,
|
||||
responseType: 'json',
|
||||
searchParams: { resource, rel: 'http://openid.net/specs/connect/1.0/issuer' },
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
});
|
||||
const body = processResponse(response);
|
||||
|
||||
const location =
|
||||
Array.isArray(body.links) &&
|
||||
body.links.find(
|
||||
(link) =>
|
||||
typeof link === 'object' &&
|
||||
link.rel === 'http://openid.net/specs/connect/1.0/issuer' &&
|
||||
link.href,
|
||||
);
|
||||
|
||||
if (!location) {
|
||||
throw new RPError({
|
||||
message: 'no issuer found in webfinger response',
|
||||
body,
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof location.href !== 'string' || !location.href.startsWith('https://')) {
|
||||
throw new RPError({
|
||||
printf: ['invalid issuer location %s', location.href],
|
||||
body,
|
||||
});
|
||||
}
|
||||
|
||||
const expectedIssuer = location.href;
|
||||
if (registry.has(expectedIssuer)) {
|
||||
return registry.get(expectedIssuer);
|
||||
}
|
||||
|
||||
const issuer = await this.discover(expectedIssuer);
|
||||
|
||||
if (issuer.issuer !== expectedIssuer) {
|
||||
registry.del(issuer.issuer);
|
||||
throw new RPError(
|
||||
'discovered issuer mismatch, expected %s, got: %s',
|
||||
expectedIssuer,
|
||||
issuer.issuer,
|
||||
);
|
||||
}
|
||||
return issuer;
|
||||
}
|
||||
|
||||
static async discover(uri) {
|
||||
const wellKnownUri = resolveWellKnownUri(uri);
|
||||
|
||||
const response = await request.call(this, {
|
||||
method: 'GET',
|
||||
responseType: 'json',
|
||||
url: wellKnownUri,
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
});
|
||||
const body = processResponse(response);
|
||||
return new Issuer({
|
||||
...ISSUER_DEFAULTS,
|
||||
...body,
|
||||
[AAD_MULTITENANT]: !!AAD_MULTITENANT_DISCOVERY.find((discoveryURL) =>
|
||||
wellKnownUri.startsWith(discoveryURL),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
async reloadJwksUri() {
|
||||
await keystore.call(this, true);
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
[inspect.custom]() {
|
||||
return `${this.constructor.name} ${inspect(this.metadata, {
|
||||
depth: Infinity,
|
||||
colors: process.stdout.isTTY,
|
||||
compact: false,
|
||||
sorted: true,
|
||||
})}`;
|
||||
}
|
||||
}
|
||||
|
||||
function resolveWellKnownUri(uri) {
|
||||
const parsed = url.parse(uri);
|
||||
if (parsed.pathname.includes('/.well-known/')) {
|
||||
return uri;
|
||||
} else {
|
||||
let pathname;
|
||||
if (parsed.pathname.endsWith('/')) {
|
||||
pathname = `${parsed.pathname}.well-known/openid-configuration`;
|
||||
} else {
|
||||
pathname = `${parsed.pathname}/.well-known/openid-configuration`;
|
||||
}
|
||||
return url.format({ ...parsed, pathname });
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Issuer;
|
||||
3
node_modules/openid-client/lib/issuer_registry.js
generated
vendored
Normal file
3
node_modules/openid-client/lib/issuer_registry.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
const LRU = require('lru-cache');
|
||||
|
||||
module.exports = new LRU({ max: 100 });
|
||||
205
node_modules/openid-client/lib/passport_strategy.js
generated
vendored
Normal file
205
node_modules/openid-client/lib/passport_strategy.js
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
const url = require('url');
|
||||
const { format } = require('util');
|
||||
|
||||
const cloneDeep = require('./helpers/deep_clone');
|
||||
const { RPError, OPError } = require('./errors');
|
||||
const { BaseClient } = require('./client');
|
||||
const { random, codeChallenge } = require('./helpers/generators');
|
||||
const pick = require('./helpers/pick');
|
||||
const { resolveResponseType, resolveRedirectUri } = require('./helpers/client');
|
||||
|
||||
function verified(err, user, info = {}) {
|
||||
if (err) {
|
||||
this.error(err);
|
||||
} else if (!user) {
|
||||
this.fail(info);
|
||||
} else {
|
||||
this.success(user, info);
|
||||
}
|
||||
}
|
||||
|
||||
function OpenIDConnectStrategy(
|
||||
{ client, params = {}, passReqToCallback = false, sessionKey, usePKCE = true, extras = {} } = {},
|
||||
verify,
|
||||
) {
|
||||
if (!(client instanceof BaseClient)) {
|
||||
throw new TypeError('client must be an instance of openid-client Client');
|
||||
}
|
||||
|
||||
if (typeof verify !== 'function') {
|
||||
throw new TypeError('verify callback must be a function');
|
||||
}
|
||||
|
||||
if (!client.issuer || !client.issuer.issuer) {
|
||||
throw new TypeError('client must have an issuer with an identifier');
|
||||
}
|
||||
|
||||
this._client = client;
|
||||
this._issuer = client.issuer;
|
||||
this._verify = verify;
|
||||
this._passReqToCallback = passReqToCallback;
|
||||
this._usePKCE = usePKCE;
|
||||
this._key = sessionKey || `oidc:${url.parse(this._issuer.issuer).hostname}`;
|
||||
this._params = cloneDeep(params);
|
||||
|
||||
// state and nonce are handled in authenticate()
|
||||
delete this._params.state;
|
||||
delete this._params.nonce;
|
||||
|
||||
this._extras = cloneDeep(extras);
|
||||
|
||||
if (!this._params.response_type) this._params.response_type = resolveResponseType.call(client);
|
||||
if (!this._params.redirect_uri) this._params.redirect_uri = resolveRedirectUri.call(client);
|
||||
if (!this._params.scope) this._params.scope = 'openid';
|
||||
|
||||
if (this._usePKCE === true) {
|
||||
const supportedMethods = Array.isArray(this._issuer.code_challenge_methods_supported)
|
||||
? this._issuer.code_challenge_methods_supported
|
||||
: false;
|
||||
|
||||
if (supportedMethods && supportedMethods.includes('S256')) {
|
||||
this._usePKCE = 'S256';
|
||||
} else if (supportedMethods && supportedMethods.includes('plain')) {
|
||||
this._usePKCE = 'plain';
|
||||
} else if (supportedMethods) {
|
||||
throw new TypeError(
|
||||
'neither code_challenge_method supported by the client is supported by the issuer',
|
||||
);
|
||||
} else {
|
||||
this._usePKCE = 'S256';
|
||||
}
|
||||
} else if (typeof this._usePKCE === 'string' && !['plain', 'S256'].includes(this._usePKCE)) {
|
||||
throw new TypeError(`${this._usePKCE} is not valid/implemented PKCE code_challenge_method`);
|
||||
}
|
||||
|
||||
this.name = url.parse(client.issuer.issuer).hostname;
|
||||
}
|
||||
|
||||
OpenIDConnectStrategy.prototype.authenticate = function authenticate(req, options) {
|
||||
(async () => {
|
||||
const client = this._client;
|
||||
if (!req.session) {
|
||||
throw new TypeError('authentication requires session support');
|
||||
}
|
||||
const reqParams = client.callbackParams(req);
|
||||
const sessionKey = this._key;
|
||||
|
||||
const { 0: parameter, length } = Object.keys(reqParams);
|
||||
|
||||
/**
|
||||
* Start authentication request if this has no authorization response parameters or
|
||||
* this might a login initiated from a third party as per
|
||||
* https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin.
|
||||
*/
|
||||
if (length === 0 || (length === 1 && parameter === 'iss')) {
|
||||
// provide options object with extra authentication parameters
|
||||
const params = {
|
||||
state: random(),
|
||||
...this._params,
|
||||
...options,
|
||||
};
|
||||
|
||||
if (!params.nonce && params.response_type.includes('id_token')) {
|
||||
params.nonce = random();
|
||||
}
|
||||
|
||||
req.session[sessionKey] = pick(params, 'nonce', 'state', 'max_age', 'response_type');
|
||||
|
||||
if (this._usePKCE && params.response_type.includes('code')) {
|
||||
const verifier = random();
|
||||
req.session[sessionKey].code_verifier = verifier;
|
||||
|
||||
switch (this._usePKCE) {
|
||||
case 'S256':
|
||||
params.code_challenge = codeChallenge(verifier);
|
||||
params.code_challenge_method = 'S256';
|
||||
break;
|
||||
case 'plain':
|
||||
params.code_challenge = verifier;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.redirect(client.authorizationUrl(params));
|
||||
return;
|
||||
}
|
||||
/* end authentication request */
|
||||
|
||||
/* start authentication response */
|
||||
|
||||
const session = req.session[sessionKey];
|
||||
if (Object.keys(session || {}).length === 0) {
|
||||
throw new Error(
|
||||
format(
|
||||
'did not find expected authorization request details in session, req.session["%s"] is %j',
|
||||
sessionKey,
|
||||
session,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
state,
|
||||
nonce,
|
||||
max_age: maxAge,
|
||||
code_verifier: codeVerifier,
|
||||
response_type: responseType,
|
||||
} = session;
|
||||
|
||||
try {
|
||||
delete req.session[sessionKey];
|
||||
} catch (err) {}
|
||||
|
||||
const opts = {
|
||||
redirect_uri: this._params.redirect_uri,
|
||||
...options,
|
||||
};
|
||||
|
||||
const checks = {
|
||||
state,
|
||||
nonce,
|
||||
max_age: maxAge,
|
||||
code_verifier: codeVerifier,
|
||||
response_type: responseType,
|
||||
};
|
||||
|
||||
const tokenset = await client.callback(opts.redirect_uri, reqParams, checks, this._extras);
|
||||
|
||||
const passReq = this._passReqToCallback;
|
||||
const loadUserinfo = this._verify.length > (passReq ? 3 : 2) && client.issuer.userinfo_endpoint;
|
||||
|
||||
const args = [tokenset, verified.bind(this)];
|
||||
|
||||
if (loadUserinfo) {
|
||||
if (!tokenset.access_token) {
|
||||
throw new RPError({
|
||||
message:
|
||||
'expected access_token to be returned when asking for userinfo in verify callback',
|
||||
tokenset,
|
||||
});
|
||||
}
|
||||
const userinfo = await client.userinfo(tokenset);
|
||||
args.splice(1, 0, userinfo);
|
||||
}
|
||||
|
||||
if (passReq) {
|
||||
args.unshift(req);
|
||||
}
|
||||
|
||||
this._verify(...args);
|
||||
/* end authentication response */
|
||||
})().catch((error) => {
|
||||
if (
|
||||
(error instanceof OPError &&
|
||||
error.error !== 'server_error' &&
|
||||
!error.error.startsWith('invalid')) ||
|
||||
error instanceof RPError
|
||||
) {
|
||||
this.fail(error);
|
||||
} else {
|
||||
this.error(error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = OpenIDConnectStrategy;
|
||||
35
node_modules/openid-client/lib/token_set.js
generated
vendored
Normal file
35
node_modules/openid-client/lib/token_set.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
const base64url = require('./helpers/base64url');
|
||||
const now = require('./helpers/unix_timestamp');
|
||||
|
||||
class TokenSet {
|
||||
constructor(values) {
|
||||
Object.assign(this, values);
|
||||
const { constructor, ...properties } = Object.getOwnPropertyDescriptors(
|
||||
this.constructor.prototype,
|
||||
);
|
||||
|
||||
Object.defineProperties(this, properties);
|
||||
}
|
||||
|
||||
set expires_in(value) {
|
||||
this.expires_at = now() + Number(value);
|
||||
}
|
||||
|
||||
get expires_in() {
|
||||
return Math.max.apply(null, [this.expires_at - now(), 0]);
|
||||
}
|
||||
|
||||
expired() {
|
||||
return this.expires_in === 0;
|
||||
}
|
||||
|
||||
claims() {
|
||||
if (!this.id_token) {
|
||||
throw new TypeError('id_token not present in TokenSet');
|
||||
}
|
||||
|
||||
return JSON.parse(base64url.decode(this.id_token.split('.')[1]));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TokenSet;
|
||||
15
node_modules/openid-client/node_modules/lru-cache/LICENSE
generated
vendored
Normal file
15
node_modules/openid-client/node_modules/lru-cache/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
166
node_modules/openid-client/node_modules/lru-cache/README.md
generated
vendored
Normal file
166
node_modules/openid-client/node_modules/lru-cache/README.md
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
# lru cache
|
||||
|
||||
A cache object that deletes the least-recently-used items.
|
||||
|
||||
[](https://travis-ci.org/isaacs/node-lru-cache) [](https://coveralls.io/github/isaacs/node-lru-cache)
|
||||
|
||||
## Installation:
|
||||
|
||||
```javascript
|
||||
npm install lru-cache --save
|
||||
```
|
||||
|
||||
## Usage:
|
||||
|
||||
```javascript
|
||||
var LRU = require("lru-cache")
|
||||
, options = { max: 500
|
||||
, length: function (n, key) { return n * 2 + key.length }
|
||||
, dispose: function (key, n) { n.close() }
|
||||
, maxAge: 1000 * 60 * 60 }
|
||||
, cache = new LRU(options)
|
||||
, otherCache = new LRU(50) // sets just the max size
|
||||
|
||||
cache.set("key", "value")
|
||||
cache.get("key") // "value"
|
||||
|
||||
// non-string keys ARE fully supported
|
||||
// but note that it must be THE SAME object, not
|
||||
// just a JSON-equivalent object.
|
||||
var someObject = { a: 1 }
|
||||
cache.set(someObject, 'a value')
|
||||
// Object keys are not toString()-ed
|
||||
cache.set('[object Object]', 'a different value')
|
||||
assert.equal(cache.get(someObject), 'a value')
|
||||
// A similar object with same keys/values won't work,
|
||||
// because it's a different object identity
|
||||
assert.equal(cache.get({ a: 1 }), undefined)
|
||||
|
||||
cache.reset() // empty the cache
|
||||
```
|
||||
|
||||
If you put more stuff in it, then items will fall out.
|
||||
|
||||
If you try to put an oversized thing in it, then it'll fall out right
|
||||
away.
|
||||
|
||||
## Options
|
||||
|
||||
* `max` The maximum size of the cache, checked by applying the length
|
||||
function to all values in the cache. Not setting this is kind of
|
||||
silly, since that's the whole purpose of this lib, but it defaults
|
||||
to `Infinity`. Setting it to a non-number or negative number will
|
||||
throw a `TypeError`. Setting it to 0 makes it be `Infinity`.
|
||||
* `maxAge` Maximum age in ms. Items are not pro-actively pruned out
|
||||
as they age, but if you try to get an item that is too old, it'll
|
||||
drop it and return undefined instead of giving it to you.
|
||||
Setting this to a negative value will make everything seem old!
|
||||
Setting it to a non-number will throw a `TypeError`.
|
||||
* `length` Function that is used to calculate the length of stored
|
||||
items. If you're storing strings or buffers, then you probably want
|
||||
to do something like `function(n, key){return n.length}`. The default is
|
||||
`function(){return 1}`, which is fine if you want to store `max`
|
||||
like-sized things. The item is passed as the first argument, and
|
||||
the key is passed as the second argumnet.
|
||||
* `dispose` Function that is called on items when they are dropped
|
||||
from the cache. This can be handy if you want to close file
|
||||
descriptors or do other cleanup tasks when items are no longer
|
||||
accessible. Called with `key, value`. It's called *before*
|
||||
actually removing the item from the internal cache, so if you want
|
||||
to immediately put it back in, you'll have to do that in a
|
||||
`nextTick` or `setTimeout` callback or it won't do anything.
|
||||
* `stale` By default, if you set a `maxAge`, it'll only actually pull
|
||||
stale items out of the cache when you `get(key)`. (That is, it's
|
||||
not pre-emptively doing a `setTimeout` or anything.) If you set
|
||||
`stale:true`, it'll return the stale value before deleting it. If
|
||||
you don't set this, then it'll return `undefined` when you try to
|
||||
get a stale entry, as if it had already been deleted.
|
||||
* `noDisposeOnSet` By default, if you set a `dispose()` method, then
|
||||
it'll be called whenever a `set()` operation overwrites an existing
|
||||
key. If you set this option, `dispose()` will only be called when a
|
||||
key falls out of the cache, not when it is overwritten.
|
||||
* `updateAgeOnGet` When using time-expiring entries with `maxAge`,
|
||||
setting this to `true` will make each item's effective time update
|
||||
to the current time whenever it is retrieved from cache, causing it
|
||||
to not expire. (It can still fall out of cache based on recency of
|
||||
use, of course.)
|
||||
|
||||
## API
|
||||
|
||||
* `set(key, value, maxAge)`
|
||||
* `get(key) => value`
|
||||
|
||||
Both of these will update the "recently used"-ness of the key.
|
||||
They do what you think. `maxAge` is optional and overrides the
|
||||
cache `maxAge` option if provided.
|
||||
|
||||
If the key is not found, `get()` will return `undefined`.
|
||||
|
||||
The key and val can be any value.
|
||||
|
||||
* `peek(key)`
|
||||
|
||||
Returns the key value (or `undefined` if not found) without
|
||||
updating the "recently used"-ness of the key.
|
||||
|
||||
(If you find yourself using this a lot, you *might* be using the
|
||||
wrong sort of data structure, but there are some use cases where
|
||||
it's handy.)
|
||||
|
||||
* `del(key)`
|
||||
|
||||
Deletes a key out of the cache.
|
||||
|
||||
* `reset()`
|
||||
|
||||
Clear the cache entirely, throwing away all values.
|
||||
|
||||
* `has(key)`
|
||||
|
||||
Check if a key is in the cache, without updating the recent-ness
|
||||
or deleting it for being stale.
|
||||
|
||||
* `forEach(function(value,key,cache), [thisp])`
|
||||
|
||||
Just like `Array.prototype.forEach`. Iterates over all the keys
|
||||
in the cache, in order of recent-ness. (Ie, more recently used
|
||||
items are iterated over first.)
|
||||
|
||||
* `rforEach(function(value,key,cache), [thisp])`
|
||||
|
||||
The same as `cache.forEach(...)` but items are iterated over in
|
||||
reverse order. (ie, less recently used items are iterated over
|
||||
first.)
|
||||
|
||||
* `keys()`
|
||||
|
||||
Return an array of the keys in the cache.
|
||||
|
||||
* `values()`
|
||||
|
||||
Return an array of the values in the cache.
|
||||
|
||||
* `length`
|
||||
|
||||
Return total length of objects in cache taking into account
|
||||
`length` options function.
|
||||
|
||||
* `itemCount`
|
||||
|
||||
Return total quantity of objects currently in cache. Note, that
|
||||
`stale` (see options) items are returned as part of this item
|
||||
count.
|
||||
|
||||
* `dump()`
|
||||
|
||||
Return an array of the cache entries ready for serialization and usage
|
||||
with 'destinationCache.load(arr)`.
|
||||
|
||||
* `load(cacheEntriesArray)`
|
||||
|
||||
Loads another cache entries array, obtained with `sourceCache.dump()`,
|
||||
into the cache. The destination cache is reset before loading new entries
|
||||
|
||||
* `prune()`
|
||||
|
||||
Manually iterates over the entire cache proactively pruning old entries
|
||||
334
node_modules/openid-client/node_modules/lru-cache/index.js
generated
vendored
Normal file
334
node_modules/openid-client/node_modules/lru-cache/index.js
generated
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
'use strict'
|
||||
|
||||
// A linked list to keep track of recently-used-ness
|
||||
const Yallist = require('yallist')
|
||||
|
||||
const MAX = Symbol('max')
|
||||
const LENGTH = Symbol('length')
|
||||
const LENGTH_CALCULATOR = Symbol('lengthCalculator')
|
||||
const ALLOW_STALE = Symbol('allowStale')
|
||||
const MAX_AGE = Symbol('maxAge')
|
||||
const DISPOSE = Symbol('dispose')
|
||||
const NO_DISPOSE_ON_SET = Symbol('noDisposeOnSet')
|
||||
const LRU_LIST = Symbol('lruList')
|
||||
const CACHE = Symbol('cache')
|
||||
const UPDATE_AGE_ON_GET = Symbol('updateAgeOnGet')
|
||||
|
||||
const naiveLength = () => 1
|
||||
|
||||
// lruList is a yallist where the head is the youngest
|
||||
// item, and the tail is the oldest. the list contains the Hit
|
||||
// objects as the entries.
|
||||
// Each Hit object has a reference to its Yallist.Node. This
|
||||
// never changes.
|
||||
//
|
||||
// cache is a Map (or PseudoMap) that matches the keys to
|
||||
// the Yallist.Node object.
|
||||
class LRUCache {
|
||||
constructor (options) {
|
||||
if (typeof options === 'number')
|
||||
options = { max: options }
|
||||
|
||||
if (!options)
|
||||
options = {}
|
||||
|
||||
if (options.max && (typeof options.max !== 'number' || options.max < 0))
|
||||
throw new TypeError('max must be a non-negative number')
|
||||
// Kind of weird to have a default max of Infinity, but oh well.
|
||||
const max = this[MAX] = options.max || Infinity
|
||||
|
||||
const lc = options.length || naiveLength
|
||||
this[LENGTH_CALCULATOR] = (typeof lc !== 'function') ? naiveLength : lc
|
||||
this[ALLOW_STALE] = options.stale || false
|
||||
if (options.maxAge && typeof options.maxAge !== 'number')
|
||||
throw new TypeError('maxAge must be a number')
|
||||
this[MAX_AGE] = options.maxAge || 0
|
||||
this[DISPOSE] = options.dispose
|
||||
this[NO_DISPOSE_ON_SET] = options.noDisposeOnSet || false
|
||||
this[UPDATE_AGE_ON_GET] = options.updateAgeOnGet || false
|
||||
this.reset()
|
||||
}
|
||||
|
||||
// resize the cache when the max changes.
|
||||
set max (mL) {
|
||||
if (typeof mL !== 'number' || mL < 0)
|
||||
throw new TypeError('max must be a non-negative number')
|
||||
|
||||
this[MAX] = mL || Infinity
|
||||
trim(this)
|
||||
}
|
||||
get max () {
|
||||
return this[MAX]
|
||||
}
|
||||
|
||||
set allowStale (allowStale) {
|
||||
this[ALLOW_STALE] = !!allowStale
|
||||
}
|
||||
get allowStale () {
|
||||
return this[ALLOW_STALE]
|
||||
}
|
||||
|
||||
set maxAge (mA) {
|
||||
if (typeof mA !== 'number')
|
||||
throw new TypeError('maxAge must be a non-negative number')
|
||||
|
||||
this[MAX_AGE] = mA
|
||||
trim(this)
|
||||
}
|
||||
get maxAge () {
|
||||
return this[MAX_AGE]
|
||||
}
|
||||
|
||||
// resize the cache when the lengthCalculator changes.
|
||||
set lengthCalculator (lC) {
|
||||
if (typeof lC !== 'function')
|
||||
lC = naiveLength
|
||||
|
||||
if (lC !== this[LENGTH_CALCULATOR]) {
|
||||
this[LENGTH_CALCULATOR] = lC
|
||||
this[LENGTH] = 0
|
||||
this[LRU_LIST].forEach(hit => {
|
||||
hit.length = this[LENGTH_CALCULATOR](hit.value, hit.key)
|
||||
this[LENGTH] += hit.length
|
||||
})
|
||||
}
|
||||
trim(this)
|
||||
}
|
||||
get lengthCalculator () { return this[LENGTH_CALCULATOR] }
|
||||
|
||||
get length () { return this[LENGTH] }
|
||||
get itemCount () { return this[LRU_LIST].length }
|
||||
|
||||
rforEach (fn, thisp) {
|
||||
thisp = thisp || this
|
||||
for (let walker = this[LRU_LIST].tail; walker !== null;) {
|
||||
const prev = walker.prev
|
||||
forEachStep(this, fn, walker, thisp)
|
||||
walker = prev
|
||||
}
|
||||
}
|
||||
|
||||
forEach (fn, thisp) {
|
||||
thisp = thisp || this
|
||||
for (let walker = this[LRU_LIST].head; walker !== null;) {
|
||||
const next = walker.next
|
||||
forEachStep(this, fn, walker, thisp)
|
||||
walker = next
|
||||
}
|
||||
}
|
||||
|
||||
keys () {
|
||||
return this[LRU_LIST].toArray().map(k => k.key)
|
||||
}
|
||||
|
||||
values () {
|
||||
return this[LRU_LIST].toArray().map(k => k.value)
|
||||
}
|
||||
|
||||
reset () {
|
||||
if (this[DISPOSE] &&
|
||||
this[LRU_LIST] &&
|
||||
this[LRU_LIST].length) {
|
||||
this[LRU_LIST].forEach(hit => this[DISPOSE](hit.key, hit.value))
|
||||
}
|
||||
|
||||
this[CACHE] = new Map() // hash of items by key
|
||||
this[LRU_LIST] = new Yallist() // list of items in order of use recency
|
||||
this[LENGTH] = 0 // length of items in the list
|
||||
}
|
||||
|
||||
dump () {
|
||||
return this[LRU_LIST].map(hit =>
|
||||
isStale(this, hit) ? false : {
|
||||
k: hit.key,
|
||||
v: hit.value,
|
||||
e: hit.now + (hit.maxAge || 0)
|
||||
}).toArray().filter(h => h)
|
||||
}
|
||||
|
||||
dumpLru () {
|
||||
return this[LRU_LIST]
|
||||
}
|
||||
|
||||
set (key, value, maxAge) {
|
||||
maxAge = maxAge || this[MAX_AGE]
|
||||
|
||||
if (maxAge && typeof maxAge !== 'number')
|
||||
throw new TypeError('maxAge must be a number')
|
||||
|
||||
const now = maxAge ? Date.now() : 0
|
||||
const len = this[LENGTH_CALCULATOR](value, key)
|
||||
|
||||
if (this[CACHE].has(key)) {
|
||||
if (len > this[MAX]) {
|
||||
del(this, this[CACHE].get(key))
|
||||
return false
|
||||
}
|
||||
|
||||
const node = this[CACHE].get(key)
|
||||
const item = node.value
|
||||
|
||||
// dispose of the old one before overwriting
|
||||
// split out into 2 ifs for better coverage tracking
|
||||
if (this[DISPOSE]) {
|
||||
if (!this[NO_DISPOSE_ON_SET])
|
||||
this[DISPOSE](key, item.value)
|
||||
}
|
||||
|
||||
item.now = now
|
||||
item.maxAge = maxAge
|
||||
item.value = value
|
||||
this[LENGTH] += len - item.length
|
||||
item.length = len
|
||||
this.get(key)
|
||||
trim(this)
|
||||
return true
|
||||
}
|
||||
|
||||
const hit = new Entry(key, value, len, now, maxAge)
|
||||
|
||||
// oversized objects fall out of cache automatically.
|
||||
if (hit.length > this[MAX]) {
|
||||
if (this[DISPOSE])
|
||||
this[DISPOSE](key, value)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
this[LENGTH] += hit.length
|
||||
this[LRU_LIST].unshift(hit)
|
||||
this[CACHE].set(key, this[LRU_LIST].head)
|
||||
trim(this)
|
||||
return true
|
||||
}
|
||||
|
||||
has (key) {
|
||||
if (!this[CACHE].has(key)) return false
|
||||
const hit = this[CACHE].get(key).value
|
||||
return !isStale(this, hit)
|
||||
}
|
||||
|
||||
get (key) {
|
||||
return get(this, key, true)
|
||||
}
|
||||
|
||||
peek (key) {
|
||||
return get(this, key, false)
|
||||
}
|
||||
|
||||
pop () {
|
||||
const node = this[LRU_LIST].tail
|
||||
if (!node)
|
||||
return null
|
||||
|
||||
del(this, node)
|
||||
return node.value
|
||||
}
|
||||
|
||||
del (key) {
|
||||
del(this, this[CACHE].get(key))
|
||||
}
|
||||
|
||||
load (arr) {
|
||||
// reset the cache
|
||||
this.reset()
|
||||
|
||||
const now = Date.now()
|
||||
// A previous serialized cache has the most recent items first
|
||||
for (let l = arr.length - 1; l >= 0; l--) {
|
||||
const hit = arr[l]
|
||||
const expiresAt = hit.e || 0
|
||||
if (expiresAt === 0)
|
||||
// the item was created without expiration in a non aged cache
|
||||
this.set(hit.k, hit.v)
|
||||
else {
|
||||
const maxAge = expiresAt - now
|
||||
// dont add already expired items
|
||||
if (maxAge > 0) {
|
||||
this.set(hit.k, hit.v, maxAge)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prune () {
|
||||
this[CACHE].forEach((value, key) => get(this, key, false))
|
||||
}
|
||||
}
|
||||
|
||||
const get = (self, key, doUse) => {
|
||||
const node = self[CACHE].get(key)
|
||||
if (node) {
|
||||
const hit = node.value
|
||||
if (isStale(self, hit)) {
|
||||
del(self, node)
|
||||
if (!self[ALLOW_STALE])
|
||||
return undefined
|
||||
} else {
|
||||
if (doUse) {
|
||||
if (self[UPDATE_AGE_ON_GET])
|
||||
node.value.now = Date.now()
|
||||
self[LRU_LIST].unshiftNode(node)
|
||||
}
|
||||
}
|
||||
return hit.value
|
||||
}
|
||||
}
|
||||
|
||||
const isStale = (self, hit) => {
|
||||
if (!hit || (!hit.maxAge && !self[MAX_AGE]))
|
||||
return false
|
||||
|
||||
const diff = Date.now() - hit.now
|
||||
return hit.maxAge ? diff > hit.maxAge
|
||||
: self[MAX_AGE] && (diff > self[MAX_AGE])
|
||||
}
|
||||
|
||||
const trim = self => {
|
||||
if (self[LENGTH] > self[MAX]) {
|
||||
for (let walker = self[LRU_LIST].tail;
|
||||
self[LENGTH] > self[MAX] && walker !== null;) {
|
||||
// We know that we're about to delete this one, and also
|
||||
// what the next least recently used key will be, so just
|
||||
// go ahead and set it now.
|
||||
const prev = walker.prev
|
||||
del(self, walker)
|
||||
walker = prev
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const del = (self, node) => {
|
||||
if (node) {
|
||||
const hit = node.value
|
||||
if (self[DISPOSE])
|
||||
self[DISPOSE](hit.key, hit.value)
|
||||
|
||||
self[LENGTH] -= hit.length
|
||||
self[CACHE].delete(hit.key)
|
||||
self[LRU_LIST].removeNode(node)
|
||||
}
|
||||
}
|
||||
|
||||
class Entry {
|
||||
constructor (key, value, length, now, maxAge) {
|
||||
this.key = key
|
||||
this.value = value
|
||||
this.length = length
|
||||
this.now = now
|
||||
this.maxAge = maxAge || 0
|
||||
}
|
||||
}
|
||||
|
||||
const forEachStep = (self, fn, node, thisp) => {
|
||||
let hit = node.value
|
||||
if (isStale(self, hit)) {
|
||||
del(self, node)
|
||||
if (!self[ALLOW_STALE])
|
||||
hit = undefined
|
||||
}
|
||||
if (hit)
|
||||
fn.call(thisp, hit.value, hit.key, self)
|
||||
}
|
||||
|
||||
module.exports = LRUCache
|
||||
34
node_modules/openid-client/node_modules/lru-cache/package.json
generated
vendored
Normal file
34
node_modules/openid-client/node_modules/lru-cache/package.json
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "lru-cache",
|
||||
"description": "A cache object that deletes the least-recently-used items.",
|
||||
"version": "6.0.0",
|
||||
"author": "Isaac Z. Schlueter <i@izs.me>",
|
||||
"keywords": [
|
||||
"mru",
|
||||
"lru",
|
||||
"cache"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "tap",
|
||||
"snap": "tap",
|
||||
"preversion": "npm test",
|
||||
"postversion": "npm publish",
|
||||
"prepublishOnly": "git push origin --follow-tags"
|
||||
},
|
||||
"main": "index.js",
|
||||
"repository": "git://github.com/isaacs/node-lru-cache.git",
|
||||
"devDependencies": {
|
||||
"benchmark": "^2.1.4",
|
||||
"tap": "^14.10.7"
|
||||
},
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"files": [
|
||||
"index.js"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
}
|
||||
15
node_modules/openid-client/node_modules/yallist/LICENSE
generated
vendored
Normal file
15
node_modules/openid-client/node_modules/yallist/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
204
node_modules/openid-client/node_modules/yallist/README.md
generated
vendored
Normal file
204
node_modules/openid-client/node_modules/yallist/README.md
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
# yallist
|
||||
|
||||
Yet Another Linked List
|
||||
|
||||
There are many doubly-linked list implementations like it, but this
|
||||
one is mine.
|
||||
|
||||
For when an array would be too big, and a Map can't be iterated in
|
||||
reverse order.
|
||||
|
||||
|
||||
[](https://travis-ci.org/isaacs/yallist) [](https://coveralls.io/github/isaacs/yallist)
|
||||
|
||||
## basic usage
|
||||
|
||||
```javascript
|
||||
var yallist = require('yallist')
|
||||
var myList = yallist.create([1, 2, 3])
|
||||
myList.push('foo')
|
||||
myList.unshift('bar')
|
||||
// of course pop() and shift() are there, too
|
||||
console.log(myList.toArray()) // ['bar', 1, 2, 3, 'foo']
|
||||
myList.forEach(function (k) {
|
||||
// walk the list head to tail
|
||||
})
|
||||
myList.forEachReverse(function (k, index, list) {
|
||||
// walk the list tail to head
|
||||
})
|
||||
var myDoubledList = myList.map(function (k) {
|
||||
return k + k
|
||||
})
|
||||
// now myDoubledList contains ['barbar', 2, 4, 6, 'foofoo']
|
||||
// mapReverse is also a thing
|
||||
var myDoubledListReverse = myList.mapReverse(function (k) {
|
||||
return k + k
|
||||
}) // ['foofoo', 6, 4, 2, 'barbar']
|
||||
|
||||
var reduced = myList.reduce(function (set, entry) {
|
||||
set += entry
|
||||
return set
|
||||
}, 'start')
|
||||
console.log(reduced) // 'startfoo123bar'
|
||||
```
|
||||
|
||||
## api
|
||||
|
||||
The whole API is considered "public".
|
||||
|
||||
Functions with the same name as an Array method work more or less the
|
||||
same way.
|
||||
|
||||
There's reverse versions of most things because that's the point.
|
||||
|
||||
### Yallist
|
||||
|
||||
Default export, the class that holds and manages a list.
|
||||
|
||||
Call it with either a forEach-able (like an array) or a set of
|
||||
arguments, to initialize the list.
|
||||
|
||||
The Array-ish methods all act like you'd expect. No magic length,
|
||||
though, so if you change that it won't automatically prune or add
|
||||
empty spots.
|
||||
|
||||
### Yallist.create(..)
|
||||
|
||||
Alias for Yallist function. Some people like factories.
|
||||
|
||||
#### yallist.head
|
||||
|
||||
The first node in the list
|
||||
|
||||
#### yallist.tail
|
||||
|
||||
The last node in the list
|
||||
|
||||
#### yallist.length
|
||||
|
||||
The number of nodes in the list. (Change this at your peril. It is
|
||||
not magic like Array length.)
|
||||
|
||||
#### yallist.toArray()
|
||||
|
||||
Convert the list to an array.
|
||||
|
||||
#### yallist.forEach(fn, [thisp])
|
||||
|
||||
Call a function on each item in the list.
|
||||
|
||||
#### yallist.forEachReverse(fn, [thisp])
|
||||
|
||||
Call a function on each item in the list, in reverse order.
|
||||
|
||||
#### yallist.get(n)
|
||||
|
||||
Get the data at position `n` in the list. If you use this a lot,
|
||||
probably better off just using an Array.
|
||||
|
||||
#### yallist.getReverse(n)
|
||||
|
||||
Get the data at position `n`, counting from the tail.
|
||||
|
||||
#### yallist.map(fn, thisp)
|
||||
|
||||
Create a new Yallist with the result of calling the function on each
|
||||
item.
|
||||
|
||||
#### yallist.mapReverse(fn, thisp)
|
||||
|
||||
Same as `map`, but in reverse.
|
||||
|
||||
#### yallist.pop()
|
||||
|
||||
Get the data from the list tail, and remove the tail from the list.
|
||||
|
||||
#### yallist.push(item, ...)
|
||||
|
||||
Insert one or more items to the tail of the list.
|
||||
|
||||
#### yallist.reduce(fn, initialValue)
|
||||
|
||||
Like Array.reduce.
|
||||
|
||||
#### yallist.reduceReverse
|
||||
|
||||
Like Array.reduce, but in reverse.
|
||||
|
||||
#### yallist.reverse
|
||||
|
||||
Reverse the list in place.
|
||||
|
||||
#### yallist.shift()
|
||||
|
||||
Get the data from the list head, and remove the head from the list.
|
||||
|
||||
#### yallist.slice([from], [to])
|
||||
|
||||
Just like Array.slice, but returns a new Yallist.
|
||||
|
||||
#### yallist.sliceReverse([from], [to])
|
||||
|
||||
Just like yallist.slice, but the result is returned in reverse.
|
||||
|
||||
#### yallist.toArray()
|
||||
|
||||
Create an array representation of the list.
|
||||
|
||||
#### yallist.toArrayReverse()
|
||||
|
||||
Create a reversed array representation of the list.
|
||||
|
||||
#### yallist.unshift(item, ...)
|
||||
|
||||
Insert one or more items to the head of the list.
|
||||
|
||||
#### yallist.unshiftNode(node)
|
||||
|
||||
Move a Node object to the front of the list. (That is, pull it out of
|
||||
wherever it lives, and make it the new head.)
|
||||
|
||||
If the node belongs to a different list, then that list will remove it
|
||||
first.
|
||||
|
||||
#### yallist.pushNode(node)
|
||||
|
||||
Move a Node object to the end of the list. (That is, pull it out of
|
||||
wherever it lives, and make it the new tail.)
|
||||
|
||||
If the node belongs to a list already, then that list will remove it
|
||||
first.
|
||||
|
||||
#### yallist.removeNode(node)
|
||||
|
||||
Remove a node from the list, preserving referential integrity of head
|
||||
and tail and other nodes.
|
||||
|
||||
Will throw an error if you try to have a list remove a node that
|
||||
doesn't belong to it.
|
||||
|
||||
### Yallist.Node
|
||||
|
||||
The class that holds the data and is actually the list.
|
||||
|
||||
Call with `var n = new Node(value, previousNode, nextNode)`
|
||||
|
||||
Note that if you do direct operations on Nodes themselves, it's very
|
||||
easy to get into weird states where the list is broken. Be careful :)
|
||||
|
||||
#### node.next
|
||||
|
||||
The next node in the list.
|
||||
|
||||
#### node.prev
|
||||
|
||||
The previous node in the list.
|
||||
|
||||
#### node.value
|
||||
|
||||
The data the node contains.
|
||||
|
||||
#### node.list
|
||||
|
||||
The list to which this node belongs. (Null if it does not belong to
|
||||
any list.)
|
||||
8
node_modules/openid-client/node_modules/yallist/iterator.js
generated
vendored
Normal file
8
node_modules/openid-client/node_modules/yallist/iterator.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict'
|
||||
module.exports = function (Yallist) {
|
||||
Yallist.prototype[Symbol.iterator] = function* () {
|
||||
for (let walker = this.head; walker; walker = walker.next) {
|
||||
yield walker.value
|
||||
}
|
||||
}
|
||||
}
|
||||
29
node_modules/openid-client/node_modules/yallist/package.json
generated
vendored
Normal file
29
node_modules/openid-client/node_modules/yallist/package.json
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "yallist",
|
||||
"version": "4.0.0",
|
||||
"description": "Yet Another Linked List",
|
||||
"main": "yallist.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"files": [
|
||||
"yallist.js",
|
||||
"iterator.js"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"tap": "^12.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tap test/*.js --100",
|
||||
"preversion": "npm test",
|
||||
"postversion": "npm publish",
|
||||
"postpublish": "git push origin --all; git push origin --tags"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/isaacs/yallist.git"
|
||||
},
|
||||
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
|
||||
"license": "ISC"
|
||||
}
|
||||
426
node_modules/openid-client/node_modules/yallist/yallist.js
generated
vendored
Normal file
426
node_modules/openid-client/node_modules/yallist/yallist.js
generated
vendored
Normal file
@@ -0,0 +1,426 @@
|
||||
'use strict'
|
||||
module.exports = Yallist
|
||||
|
||||
Yallist.Node = Node
|
||||
Yallist.create = Yallist
|
||||
|
||||
function Yallist (list) {
|
||||
var self = this
|
||||
if (!(self instanceof Yallist)) {
|
||||
self = new Yallist()
|
||||
}
|
||||
|
||||
self.tail = null
|
||||
self.head = null
|
||||
self.length = 0
|
||||
|
||||
if (list && typeof list.forEach === 'function') {
|
||||
list.forEach(function (item) {
|
||||
self.push(item)
|
||||
})
|
||||
} else if (arguments.length > 0) {
|
||||
for (var i = 0, l = arguments.length; i < l; i++) {
|
||||
self.push(arguments[i])
|
||||
}
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
Yallist.prototype.removeNode = function (node) {
|
||||
if (node.list !== this) {
|
||||
throw new Error('removing node which does not belong to this list')
|
||||
}
|
||||
|
||||
var next = node.next
|
||||
var prev = node.prev
|
||||
|
||||
if (next) {
|
||||
next.prev = prev
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
prev.next = next
|
||||
}
|
||||
|
||||
if (node === this.head) {
|
||||
this.head = next
|
||||
}
|
||||
if (node === this.tail) {
|
||||
this.tail = prev
|
||||
}
|
||||
|
||||
node.list.length--
|
||||
node.next = null
|
||||
node.prev = null
|
||||
node.list = null
|
||||
|
||||
return next
|
||||
}
|
||||
|
||||
Yallist.prototype.unshiftNode = function (node) {
|
||||
if (node === this.head) {
|
||||
return
|
||||
}
|
||||
|
||||
if (node.list) {
|
||||
node.list.removeNode(node)
|
||||
}
|
||||
|
||||
var head = this.head
|
||||
node.list = this
|
||||
node.next = head
|
||||
if (head) {
|
||||
head.prev = node
|
||||
}
|
||||
|
||||
this.head = node
|
||||
if (!this.tail) {
|
||||
this.tail = node
|
||||
}
|
||||
this.length++
|
||||
}
|
||||
|
||||
Yallist.prototype.pushNode = function (node) {
|
||||
if (node === this.tail) {
|
||||
return
|
||||
}
|
||||
|
||||
if (node.list) {
|
||||
node.list.removeNode(node)
|
||||
}
|
||||
|
||||
var tail = this.tail
|
||||
node.list = this
|
||||
node.prev = tail
|
||||
if (tail) {
|
||||
tail.next = node
|
||||
}
|
||||
|
||||
this.tail = node
|
||||
if (!this.head) {
|
||||
this.head = node
|
||||
}
|
||||
this.length++
|
||||
}
|
||||
|
||||
Yallist.prototype.push = function () {
|
||||
for (var i = 0, l = arguments.length; i < l; i++) {
|
||||
push(this, arguments[i])
|
||||
}
|
||||
return this.length
|
||||
}
|
||||
|
||||
Yallist.prototype.unshift = function () {
|
||||
for (var i = 0, l = arguments.length; i < l; i++) {
|
||||
unshift(this, arguments[i])
|
||||
}
|
||||
return this.length
|
||||
}
|
||||
|
||||
Yallist.prototype.pop = function () {
|
||||
if (!this.tail) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
var res = this.tail.value
|
||||
this.tail = this.tail.prev
|
||||
if (this.tail) {
|
||||
this.tail.next = null
|
||||
} else {
|
||||
this.head = null
|
||||
}
|
||||
this.length--
|
||||
return res
|
||||
}
|
||||
|
||||
Yallist.prototype.shift = function () {
|
||||
if (!this.head) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
var res = this.head.value
|
||||
this.head = this.head.next
|
||||
if (this.head) {
|
||||
this.head.prev = null
|
||||
} else {
|
||||
this.tail = null
|
||||
}
|
||||
this.length--
|
||||
return res
|
||||
}
|
||||
|
||||
Yallist.prototype.forEach = function (fn, thisp) {
|
||||
thisp = thisp || this
|
||||
for (var walker = this.head, i = 0; walker !== null; i++) {
|
||||
fn.call(thisp, walker.value, i, this)
|
||||
walker = walker.next
|
||||
}
|
||||
}
|
||||
|
||||
Yallist.prototype.forEachReverse = function (fn, thisp) {
|
||||
thisp = thisp || this
|
||||
for (var walker = this.tail, i = this.length - 1; walker !== null; i--) {
|
||||
fn.call(thisp, walker.value, i, this)
|
||||
walker = walker.prev
|
||||
}
|
||||
}
|
||||
|
||||
Yallist.prototype.get = function (n) {
|
||||
for (var i = 0, walker = this.head; walker !== null && i < n; i++) {
|
||||
// abort out of the list early if we hit a cycle
|
||||
walker = walker.next
|
||||
}
|
||||
if (i === n && walker !== null) {
|
||||
return walker.value
|
||||
}
|
||||
}
|
||||
|
||||
Yallist.prototype.getReverse = function (n) {
|
||||
for (var i = 0, walker = this.tail; walker !== null && i < n; i++) {
|
||||
// abort out of the list early if we hit a cycle
|
||||
walker = walker.prev
|
||||
}
|
||||
if (i === n && walker !== null) {
|
||||
return walker.value
|
||||
}
|
||||
}
|
||||
|
||||
Yallist.prototype.map = function (fn, thisp) {
|
||||
thisp = thisp || this
|
||||
var res = new Yallist()
|
||||
for (var walker = this.head; walker !== null;) {
|
||||
res.push(fn.call(thisp, walker.value, this))
|
||||
walker = walker.next
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
Yallist.prototype.mapReverse = function (fn, thisp) {
|
||||
thisp = thisp || this
|
||||
var res = new Yallist()
|
||||
for (var walker = this.tail; walker !== null;) {
|
||||
res.push(fn.call(thisp, walker.value, this))
|
||||
walker = walker.prev
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
Yallist.prototype.reduce = function (fn, initial) {
|
||||
var acc
|
||||
var walker = this.head
|
||||
if (arguments.length > 1) {
|
||||
acc = initial
|
||||
} else if (this.head) {
|
||||
walker = this.head.next
|
||||
acc = this.head.value
|
||||
} else {
|
||||
throw new TypeError('Reduce of empty list with no initial value')
|
||||
}
|
||||
|
||||
for (var i = 0; walker !== null; i++) {
|
||||
acc = fn(acc, walker.value, i)
|
||||
walker = walker.next
|
||||
}
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
Yallist.prototype.reduceReverse = function (fn, initial) {
|
||||
var acc
|
||||
var walker = this.tail
|
||||
if (arguments.length > 1) {
|
||||
acc = initial
|
||||
} else if (this.tail) {
|
||||
walker = this.tail.prev
|
||||
acc = this.tail.value
|
||||
} else {
|
||||
throw new TypeError('Reduce of empty list with no initial value')
|
||||
}
|
||||
|
||||
for (var i = this.length - 1; walker !== null; i--) {
|
||||
acc = fn(acc, walker.value, i)
|
||||
walker = walker.prev
|
||||
}
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
Yallist.prototype.toArray = function () {
|
||||
var arr = new Array(this.length)
|
||||
for (var i = 0, walker = this.head; walker !== null; i++) {
|
||||
arr[i] = walker.value
|
||||
walker = walker.next
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
Yallist.prototype.toArrayReverse = function () {
|
||||
var arr = new Array(this.length)
|
||||
for (var i = 0, walker = this.tail; walker !== null; i++) {
|
||||
arr[i] = walker.value
|
||||
walker = walker.prev
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
Yallist.prototype.slice = function (from, to) {
|
||||
to = to || this.length
|
||||
if (to < 0) {
|
||||
to += this.length
|
||||
}
|
||||
from = from || 0
|
||||
if (from < 0) {
|
||||
from += this.length
|
||||
}
|
||||
var ret = new Yallist()
|
||||
if (to < from || to < 0) {
|
||||
return ret
|
||||
}
|
||||
if (from < 0) {
|
||||
from = 0
|
||||
}
|
||||
if (to > this.length) {
|
||||
to = this.length
|
||||
}
|
||||
for (var i = 0, walker = this.head; walker !== null && i < from; i++) {
|
||||
walker = walker.next
|
||||
}
|
||||
for (; walker !== null && i < to; i++, walker = walker.next) {
|
||||
ret.push(walker.value)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
Yallist.prototype.sliceReverse = function (from, to) {
|
||||
to = to || this.length
|
||||
if (to < 0) {
|
||||
to += this.length
|
||||
}
|
||||
from = from || 0
|
||||
if (from < 0) {
|
||||
from += this.length
|
||||
}
|
||||
var ret = new Yallist()
|
||||
if (to < from || to < 0) {
|
||||
return ret
|
||||
}
|
||||
if (from < 0) {
|
||||
from = 0
|
||||
}
|
||||
if (to > this.length) {
|
||||
to = this.length
|
||||
}
|
||||
for (var i = this.length, walker = this.tail; walker !== null && i > to; i--) {
|
||||
walker = walker.prev
|
||||
}
|
||||
for (; walker !== null && i > from; i--, walker = walker.prev) {
|
||||
ret.push(walker.value)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
Yallist.prototype.splice = function (start, deleteCount, ...nodes) {
|
||||
if (start > this.length) {
|
||||
start = this.length - 1
|
||||
}
|
||||
if (start < 0) {
|
||||
start = this.length + start;
|
||||
}
|
||||
|
||||
for (var i = 0, walker = this.head; walker !== null && i < start; i++) {
|
||||
walker = walker.next
|
||||
}
|
||||
|
||||
var ret = []
|
||||
for (var i = 0; walker && i < deleteCount; i++) {
|
||||
ret.push(walker.value)
|
||||
walker = this.removeNode(walker)
|
||||
}
|
||||
if (walker === null) {
|
||||
walker = this.tail
|
||||
}
|
||||
|
||||
if (walker !== this.head && walker !== this.tail) {
|
||||
walker = walker.prev
|
||||
}
|
||||
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
walker = insert(this, walker, nodes[i])
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Yallist.prototype.reverse = function () {
|
||||
var head = this.head
|
||||
var tail = this.tail
|
||||
for (var walker = head; walker !== null; walker = walker.prev) {
|
||||
var p = walker.prev
|
||||
walker.prev = walker.next
|
||||
walker.next = p
|
||||
}
|
||||
this.head = tail
|
||||
this.tail = head
|
||||
return this
|
||||
}
|
||||
|
||||
function insert (self, node, value) {
|
||||
var inserted = node === self.head ?
|
||||
new Node(value, null, node, self) :
|
||||
new Node(value, node, node.next, self)
|
||||
|
||||
if (inserted.next === null) {
|
||||
self.tail = inserted
|
||||
}
|
||||
if (inserted.prev === null) {
|
||||
self.head = inserted
|
||||
}
|
||||
|
||||
self.length++
|
||||
|
||||
return inserted
|
||||
}
|
||||
|
||||
function push (self, item) {
|
||||
self.tail = new Node(item, self.tail, null, self)
|
||||
if (!self.head) {
|
||||
self.head = self.tail
|
||||
}
|
||||
self.length++
|
||||
}
|
||||
|
||||
function unshift (self, item) {
|
||||
self.head = new Node(item, null, self.head, self)
|
||||
if (!self.tail) {
|
||||
self.tail = self.head
|
||||
}
|
||||
self.length++
|
||||
}
|
||||
|
||||
function Node (value, prev, next, list) {
|
||||
if (!(this instanceof Node)) {
|
||||
return new Node(value, prev, next, list)
|
||||
}
|
||||
|
||||
this.list = list
|
||||
this.value = value
|
||||
|
||||
if (prev) {
|
||||
prev.next = this
|
||||
this.prev = prev
|
||||
} else {
|
||||
this.prev = null
|
||||
}
|
||||
|
||||
if (next) {
|
||||
next.prev = this
|
||||
this.next = next
|
||||
} else {
|
||||
this.next = null
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// add if support for Symbol.iterator is present
|
||||
require('./iterator.js')(Yallist)
|
||||
} catch (er) {}
|
||||
106
node_modules/openid-client/package.json
generated
vendored
Normal file
106
node_modules/openid-client/package.json
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"name": "openid-client",
|
||||
"version": "5.7.1",
|
||||
"description": "OpenID Connect Relying Party (RP, Client) implementation for Node.js runtime, supports passportjs",
|
||||
"keywords": [
|
||||
"auth",
|
||||
"authentication",
|
||||
"basic",
|
||||
"certified",
|
||||
"client",
|
||||
"connect",
|
||||
"dynamic",
|
||||
"electron",
|
||||
"hybrid",
|
||||
"identity",
|
||||
"implicit",
|
||||
"oauth",
|
||||
"oauth2",
|
||||
"oidc",
|
||||
"openid",
|
||||
"passport",
|
||||
"relying party",
|
||||
"strategy"
|
||||
],
|
||||
"homepage": "https://github.com/panva/openid-client",
|
||||
"repository": "panva/openid-client",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "Filip Skokan <panva.ip@gmail.com>",
|
||||
"exports": {
|
||||
"types": "./types/index.d.ts",
|
||||
"import": "./lib/index.mjs",
|
||||
"require": "./lib/index.js"
|
||||
},
|
||||
"main": "./lib/index.js",
|
||||
"types": "./types/index.d.ts",
|
||||
"files": [
|
||||
"lib",
|
||||
"types/index.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"format": "npx prettier --loglevel silent --write ./lib ./test ./certification ./types",
|
||||
"test": "mocha test/**/*.test.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"jose": "^4.15.9",
|
||||
"lru-cache": "^6.0.0",
|
||||
"object-hash": "^2.2.0",
|
||||
"oidc-token-hash": "^5.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.18.106",
|
||||
"@types/passport": "^1.0.16",
|
||||
"base64url": "^3.0.1",
|
||||
"chai": "^4.5.0",
|
||||
"mocha": "^10.7.3",
|
||||
"nock": "^13.5.5",
|
||||
"prettier": "^2.8.8",
|
||||
"readable-mock-req": "^0.2.2",
|
||||
"sinon": "^9.2.4",
|
||||
"timekeeper": "^2.3.1"
|
||||
},
|
||||
"standard-version": {
|
||||
"scripts": {
|
||||
"postchangelog": "sed -i '' -e 's/### \\[/## [/g' CHANGELOG.md"
|
||||
},
|
||||
"types": [
|
||||
{
|
||||
"type": "feat",
|
||||
"section": "Features"
|
||||
},
|
||||
{
|
||||
"type": "fix",
|
||||
"section": "Fixes"
|
||||
},
|
||||
{
|
||||
"type": "chore",
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"type": "docs",
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"type": "style",
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"type": "refactor",
|
||||
"section": "Refactor",
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"type": "perf",
|
||||
"section": "Performance",
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"type": "test",
|
||||
"hidden": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
623
node_modules/openid-client/types/index.d.ts
generated
vendored
Normal file
623
node_modules/openid-client/types/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,623 @@
|
||||
/// <reference types="node" />
|
||||
// TypeScript Version: 3.6
|
||||
|
||||
import * as http from 'http';
|
||||
import * as https from 'https';
|
||||
import * as http2 from 'http2';
|
||||
|
||||
import { URL } from 'url';
|
||||
import * as jose from 'jose';
|
||||
import * as crypto from 'crypto';
|
||||
import { format } from 'util';
|
||||
|
||||
export type HttpOptions = Partial<
|
||||
Pick<
|
||||
https.RequestOptions,
|
||||
| 'agent'
|
||||
| 'ca'
|
||||
| 'cert'
|
||||
| 'crl'
|
||||
| 'headers'
|
||||
| 'key'
|
||||
| 'lookup'
|
||||
| 'passphrase'
|
||||
| 'pfx'
|
||||
| 'timeout'
|
||||
>
|
||||
>;
|
||||
export type RetryFunction = (retry: number, error: Error) => number;
|
||||
export type CustomHttpOptionsProvider = (
|
||||
url: URL,
|
||||
options: Omit<https.RequestOptions, keyof URL>,
|
||||
) => HttpOptions;
|
||||
export type TokenTypeHint = 'access_token' | 'refresh_token' | string;
|
||||
export type DPoPInput = crypto.KeyObject | Parameters<typeof crypto.createPrivateKey>[0];
|
||||
|
||||
interface UnknownObject {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export const custom: {
|
||||
setHttpOptionsDefaults(params: HttpOptions): undefined;
|
||||
readonly http_options: unique symbol;
|
||||
readonly clock_tolerance: unique symbol;
|
||||
};
|
||||
|
||||
export type ResponseType = 'code' | 'id_token' | 'code id_token' | 'none' | string;
|
||||
export type ClientAuthMethod =
|
||||
| 'client_secret_basic'
|
||||
| 'client_secret_post'
|
||||
| 'client_secret_jwt'
|
||||
| 'private_key_jwt'
|
||||
| 'tls_client_auth'
|
||||
| 'self_signed_tls_client_auth'
|
||||
| 'none';
|
||||
|
||||
export interface ClientMetadata {
|
||||
// important
|
||||
client_id: string;
|
||||
id_token_signed_response_alg?: string;
|
||||
token_endpoint_auth_method?: ClientAuthMethod;
|
||||
client_secret?: string;
|
||||
redirect_uris?: string[];
|
||||
response_types?: ResponseType[];
|
||||
post_logout_redirect_uris?: string[];
|
||||
default_max_age?: number;
|
||||
require_auth_time?: boolean;
|
||||
tls_client_certificate_bound_access_tokens?: boolean;
|
||||
request_object_signing_alg?: string;
|
||||
|
||||
// less important
|
||||
id_token_encrypted_response_alg?: string;
|
||||
id_token_encrypted_response_enc?: string;
|
||||
introspection_endpoint_auth_method?: ClientAuthMethod;
|
||||
introspection_endpoint_auth_signing_alg?: string;
|
||||
request_object_encryption_alg?: string;
|
||||
request_object_encryption_enc?: string;
|
||||
revocation_endpoint_auth_method?: ClientAuthMethod;
|
||||
revocation_endpoint_auth_signing_alg?: string;
|
||||
token_endpoint_auth_signing_alg?: string;
|
||||
userinfo_encrypted_response_alg?: string;
|
||||
userinfo_encrypted_response_enc?: string;
|
||||
userinfo_signed_response_alg?: string;
|
||||
authorization_encrypted_response_alg?: string;
|
||||
authorization_encrypted_response_enc?: string;
|
||||
authorization_signed_response_alg?: string;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface ClaimsParameterMember {
|
||||
essential?: boolean;
|
||||
value?: string;
|
||||
values?: string[];
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface AuthorizationParameters {
|
||||
acr_values?: string;
|
||||
audience?: string;
|
||||
claims?:
|
||||
| string
|
||||
| {
|
||||
id_token?: {
|
||||
[key: string]: null | ClaimsParameterMember;
|
||||
};
|
||||
userinfo?: {
|
||||
[key: string]: null | ClaimsParameterMember;
|
||||
};
|
||||
};
|
||||
claims_locales?: string;
|
||||
client_id?: string;
|
||||
code_challenge_method?: string;
|
||||
code_challenge?: string;
|
||||
display?: string;
|
||||
id_token_hint?: string;
|
||||
login_hint?: string;
|
||||
max_age?: number;
|
||||
nonce?: string;
|
||||
prompt?: string;
|
||||
redirect_uri?: string;
|
||||
registration?: string;
|
||||
request_uri?: string;
|
||||
request?: string;
|
||||
resource?: string | string[];
|
||||
response_mode?: string;
|
||||
response_type?: string;
|
||||
scope?: string;
|
||||
state?: string;
|
||||
ui_locales?: string;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface EndSessionParameters {
|
||||
id_token_hint?: TokenSet | string;
|
||||
post_logout_redirect_uri?: string;
|
||||
state?: string;
|
||||
client_id?: string;
|
||||
logout_hint?: string;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface CallbackParamsType {
|
||||
access_token?: string;
|
||||
code?: string;
|
||||
error?: string;
|
||||
error_description?: string;
|
||||
error_uri?: string;
|
||||
expires_in?: string;
|
||||
id_token?: string;
|
||||
state?: string;
|
||||
token_type?: string;
|
||||
session_state?: string;
|
||||
response?: string;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface OAuthCallbackChecks {
|
||||
response_type?: string;
|
||||
state?: string;
|
||||
code_verifier?: string;
|
||||
jarm?: boolean;
|
||||
scope?: string; // TODO: remove in v6.x
|
||||
}
|
||||
|
||||
export interface OpenIDCallbackChecks extends OAuthCallbackChecks {
|
||||
max_age?: number;
|
||||
nonce?: string;
|
||||
}
|
||||
|
||||
export interface CallbackExtras {
|
||||
exchangeBody?: object;
|
||||
clientAssertionPayload?: object;
|
||||
DPoP?: DPoPInput;
|
||||
}
|
||||
|
||||
export interface RefreshExtras {
|
||||
exchangeBody?: object;
|
||||
clientAssertionPayload?: object;
|
||||
DPoP?: DPoPInput;
|
||||
}
|
||||
|
||||
export interface GrantBody {
|
||||
grant_type: string;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface GrantExtras {
|
||||
clientAssertionPayload?: object;
|
||||
DPoP?: DPoPInput;
|
||||
}
|
||||
|
||||
export interface IntrospectExtras {
|
||||
introspectBody?: object;
|
||||
clientAssertionPayload?: object;
|
||||
}
|
||||
|
||||
export interface RevokeExtras {
|
||||
revokeBody?: object;
|
||||
clientAssertionPayload?: object;
|
||||
}
|
||||
|
||||
export interface RequestObjectPayload extends AuthorizationParameters {
|
||||
client_id?: string;
|
||||
iss?: string;
|
||||
aud?: string;
|
||||
iat?: number;
|
||||
exp?: number;
|
||||
jti?: string;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface RegisterOther {
|
||||
jwks?: { keys: jose.JWK[] };
|
||||
initialAccessToken?: string;
|
||||
}
|
||||
|
||||
export interface DeviceAuthorizationParameters {
|
||||
client_id?: string;
|
||||
scope?: string;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface DeviceAuthorizationExtras {
|
||||
exchangeBody?: object;
|
||||
clientAssertionPayload?: object;
|
||||
DPoP?: DPoPInput;
|
||||
}
|
||||
|
||||
export interface PushedAuthorizationRequestExtras {
|
||||
clientAssertionPayload?: object;
|
||||
}
|
||||
|
||||
export type Address<ExtendedAddress extends {} = UnknownObject> = Override<
|
||||
{
|
||||
formatted?: string;
|
||||
street_address?: string;
|
||||
locality?: string;
|
||||
region?: string;
|
||||
postal_code?: string;
|
||||
country?: string;
|
||||
},
|
||||
ExtendedAddress
|
||||
>;
|
||||
|
||||
export type UserinfoResponse<
|
||||
UserInfo extends {} = UnknownObject,
|
||||
ExtendedAddress extends {} = UnknownObject,
|
||||
> = Override<
|
||||
{
|
||||
sub: string;
|
||||
name?: string;
|
||||
given_name?: string;
|
||||
family_name?: string;
|
||||
middle_name?: string;
|
||||
nickname?: string;
|
||||
preferred_username?: string;
|
||||
profile?: string;
|
||||
picture?: string;
|
||||
website?: string;
|
||||
email?: string;
|
||||
email_verified?: boolean;
|
||||
gender?: string;
|
||||
birthdate?: string;
|
||||
zoneinfo?: string;
|
||||
locale?: string;
|
||||
phone_number?: string;
|
||||
updated_at?: number;
|
||||
address?: Address<ExtendedAddress>;
|
||||
},
|
||||
UserInfo
|
||||
>;
|
||||
|
||||
export interface IntrospectionResponse {
|
||||
active: boolean;
|
||||
client_id?: string;
|
||||
exp?: number;
|
||||
iat?: number;
|
||||
sid?: string;
|
||||
iss?: string;
|
||||
jti?: string;
|
||||
username?: string;
|
||||
aud?: string | string[];
|
||||
scope: string;
|
||||
sub?: string;
|
||||
nbf?: number;
|
||||
token_type?: string;
|
||||
cnf?: {
|
||||
'x5t#S256'?: string;
|
||||
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface ClientOptions {
|
||||
additionalAuthorizedParties?: string | string[];
|
||||
}
|
||||
|
||||
export type Client = InstanceType<Issuer['Client']>;
|
||||
declare class BaseClient {
|
||||
constructor(metadata: ClientMetadata, jwks?: { keys: jose.JWK[] }, options?: ClientOptions);
|
||||
[custom.http_options]: CustomHttpOptionsProvider;
|
||||
[custom.clock_tolerance]: number;
|
||||
metadata: ClientMetadata;
|
||||
issuer: Issuer<this>;
|
||||
static issuer: Issuer<BaseClient>;
|
||||
|
||||
authorizationUrl(parameters?: AuthorizationParameters): string;
|
||||
endSessionUrl(parameters?: EndSessionParameters): string;
|
||||
callbackParams(
|
||||
input: string | http.IncomingMessage | http2.Http2ServerRequest,
|
||||
): CallbackParamsType;
|
||||
callback(
|
||||
redirectUri: string | undefined,
|
||||
parameters: CallbackParamsType,
|
||||
checks?: OpenIDCallbackChecks,
|
||||
extras?: CallbackExtras,
|
||||
): Promise<TokenSet>;
|
||||
oauthCallback(
|
||||
redirectUri: string | undefined,
|
||||
parameters: CallbackParamsType,
|
||||
checks?: OAuthCallbackChecks,
|
||||
extras?: CallbackExtras,
|
||||
): Promise<TokenSet>;
|
||||
refresh(refreshToken: TokenSet | string, extras?: RefreshExtras): Promise<TokenSet>;
|
||||
userinfo<TUserInfo extends {} = UnknownObject, TAddress extends {} = UnknownObject>(
|
||||
accessToken: TokenSet | string,
|
||||
options?: {
|
||||
method?: 'GET' | 'POST';
|
||||
via?: 'header' | 'body';
|
||||
tokenType?: string;
|
||||
params?: object;
|
||||
DPoP?: DPoPInput;
|
||||
},
|
||||
): Promise<UserinfoResponse<TUserInfo, TAddress>>;
|
||||
requestResource(
|
||||
resourceUrl: string | URL,
|
||||
accessToken: TokenSet | string,
|
||||
options?: {
|
||||
headers?: object;
|
||||
body?: string | Buffer;
|
||||
method?: 'GET' | 'POST' | 'PUT' | 'HEAD' | 'DELETE' | 'OPTIONS' | 'TRACE' | 'PATCH';
|
||||
tokenType?: string;
|
||||
DPoP?: DPoPInput;
|
||||
},
|
||||
): Promise<{ body?: Buffer } & http.IncomingMessage>;
|
||||
grant(body: GrantBody, extras?: GrantExtras): Promise<TokenSet>;
|
||||
introspect(
|
||||
token: string,
|
||||
tokenTypeHint?: TokenTypeHint,
|
||||
extras?: IntrospectExtras,
|
||||
): Promise<IntrospectionResponse>;
|
||||
revoke(token: string, tokenTypeHint?: TokenTypeHint, extras?: RevokeExtras): Promise<undefined>;
|
||||
requestObject(payload: RequestObjectPayload): Promise<string>;
|
||||
deviceAuthorization(
|
||||
parameters?: DeviceAuthorizationParameters,
|
||||
extras?: DeviceAuthorizationExtras,
|
||||
): Promise<DeviceFlowHandle<BaseClient>>;
|
||||
pushedAuthorizationRequest(
|
||||
parameters?: AuthorizationParameters,
|
||||
extras?: PushedAuthorizationRequestExtras,
|
||||
): Promise<{
|
||||
request_uri: string;
|
||||
expires_in: number;
|
||||
[key: string]: unknown;
|
||||
}>;
|
||||
static register(metadata: object, other?: RegisterOther & ClientOptions): Promise<BaseClient>;
|
||||
static fromUri(
|
||||
registrationClientUri: string,
|
||||
registrationAccessToken: string,
|
||||
jwks?: { keys: jose.JWK[] },
|
||||
clientOptions?: ClientOptions,
|
||||
): Promise<BaseClient>;
|
||||
static [custom.http_options]: CustomHttpOptionsProvider;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface DeviceFlowPollOptions {
|
||||
// @ts-ignore
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
|
||||
export class DeviceFlowHandle<TClient extends BaseClient = BaseClient> {
|
||||
poll(options?: DeviceFlowPollOptions): Promise<TokenSet>;
|
||||
abort(): void;
|
||||
expired(): boolean;
|
||||
expires_at: number;
|
||||
client: TClient;
|
||||
user_code: string;
|
||||
device_code: string;
|
||||
verification_uri: string;
|
||||
verification_uri_complete: string;
|
||||
expires_in: number;
|
||||
}
|
||||
|
||||
export interface IssuerMetadata {
|
||||
issuer: string;
|
||||
authorization_endpoint?: string;
|
||||
token_endpoint?: string;
|
||||
jwks_uri?: string;
|
||||
userinfo_endpoint?: string;
|
||||
revocation_endpoint?: string;
|
||||
end_session_endpoint?: string;
|
||||
registration_endpoint?: string;
|
||||
token_endpoint_auth_methods_supported?: string[];
|
||||
token_endpoint_auth_signing_alg_values_supported?: string[];
|
||||
introspection_endpoint_auth_methods_supported?: string[];
|
||||
introspection_endpoint_auth_signing_alg_values_supported?: string[];
|
||||
revocation_endpoint_auth_methods_supported?: string[];
|
||||
revocation_endpoint_auth_signing_alg_values_supported?: string[];
|
||||
request_object_signing_alg_values_supported?: string[];
|
||||
mtls_endpoint_aliases?: MtlsEndpointAliases;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface MtlsEndpointAliases {
|
||||
token_endpoint?: string;
|
||||
userinfo_endpoint?: string;
|
||||
revocation_endpoint?: string;
|
||||
introspection_endpoint?: string;
|
||||
device_authorization_endpoint?: string;
|
||||
}
|
||||
|
||||
export interface TypeOfGenericClient<TClient extends BaseClient = BaseClient> {
|
||||
new (metadata: ClientMetadata, jwks?: { keys: jose.JWK[] }, options?: ClientOptions): TClient;
|
||||
[custom.http_options]: CustomHttpOptionsProvider;
|
||||
[custom.clock_tolerance]: number;
|
||||
}
|
||||
|
||||
export class Issuer<TClient extends BaseClient = BaseClient> {
|
||||
constructor(metadata: IssuerMetadata);
|
||||
|
||||
Client: TypeOfGenericClient<TClient>;
|
||||
|
||||
FAPI1Client: TypeOfGenericClient<TClient>;
|
||||
FAPI2Client: TypeOfGenericClient<TClient>;
|
||||
|
||||
metadata: IssuerMetadata;
|
||||
[custom.http_options]: CustomHttpOptionsProvider;
|
||||
static discover(issuer: string): Promise<Issuer<BaseClient>>;
|
||||
static webfinger(input: string): Promise<Issuer<BaseClient>>;
|
||||
static [custom.http_options]: CustomHttpOptionsProvider;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface TokenSetParameters {
|
||||
access_token?: string;
|
||||
token_type?: string;
|
||||
id_token?: string;
|
||||
refresh_token?: string;
|
||||
scope?: string;
|
||||
|
||||
expires_at?: number;
|
||||
session_state?: string;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface IdTokenClaims extends UserinfoResponse {
|
||||
acr?: string;
|
||||
amr?: string[];
|
||||
at_hash?: string;
|
||||
aud: string | string[];
|
||||
auth_time?: number;
|
||||
azp?: string;
|
||||
c_hash?: string;
|
||||
exp: number;
|
||||
iat: number;
|
||||
iss: string;
|
||||
nonce?: string;
|
||||
s_hash?: string;
|
||||
sub: string;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export class TokenSet implements TokenSetParameters {
|
||||
access_token?: string;
|
||||
token_type?: string;
|
||||
id_token?: string;
|
||||
refresh_token?: string;
|
||||
expires_in?: number;
|
||||
expires_at?: number;
|
||||
session_state?: string;
|
||||
scope?: string;
|
||||
|
||||
constructor(input?: TokenSetParameters);
|
||||
|
||||
expired(): boolean;
|
||||
claims(): IdTokenClaims;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export type StrategyVerifyCallbackUserInfo<
|
||||
TUser,
|
||||
TUserInfo extends {} = UnknownObject,
|
||||
TAddress extends {} = UnknownObject,
|
||||
> = (
|
||||
tokenset: TokenSet,
|
||||
userinfo: UserinfoResponse<TUserInfo, TAddress>,
|
||||
done: (err: any, user?: TUser) => void,
|
||||
) => void;
|
||||
export type StrategyVerifyCallback<TUser> = (
|
||||
tokenset: TokenSet,
|
||||
done: (err: any, user?: TUser) => void,
|
||||
) => void;
|
||||
export type StrategyVerifyCallbackReqUserInfo<
|
||||
TUser,
|
||||
TUserInfo extends {} = UnknownObject,
|
||||
TAddress extends {} = UnknownObject,
|
||||
> = (
|
||||
req: http.IncomingMessage,
|
||||
tokenset: TokenSet,
|
||||
userinfo: UserinfoResponse<TUserInfo, TAddress>,
|
||||
done: (err: any, user?: TUser) => void,
|
||||
) => void;
|
||||
export type StrategyVerifyCallbackReq<TUser> = (
|
||||
req: http.IncomingMessage,
|
||||
tokenset: TokenSet,
|
||||
done: (err: any, user?: TUser) => void,
|
||||
) => void;
|
||||
|
||||
export interface StrategyOptions<TClient extends BaseClient = BaseClient> {
|
||||
client: TClient;
|
||||
params?: AuthorizationParameters;
|
||||
extras?: CallbackExtras;
|
||||
passReqToCallback?: boolean;
|
||||
usePKCE?: boolean | string;
|
||||
sessionKey?: string;
|
||||
}
|
||||
|
||||
export class Strategy<TUser, TClient extends BaseClient = BaseClient> {
|
||||
constructor(
|
||||
options: StrategyOptions<TClient>,
|
||||
verify:
|
||||
| StrategyVerifyCallback<TUser>
|
||||
| StrategyVerifyCallbackUserInfo<TUser>
|
||||
| StrategyVerifyCallbackReq<TUser>
|
||||
| StrategyVerifyCallbackReqUserInfo<TUser>,
|
||||
);
|
||||
|
||||
authenticate(req: any, options?: any): void;
|
||||
success(user: any, info?: any): void;
|
||||
fail(challenge: any, status: number): void;
|
||||
fail(status: number): void;
|
||||
redirect(url: string, status?: number): void;
|
||||
pass(): void;
|
||||
error(err: Error): void;
|
||||
}
|
||||
|
||||
export namespace generators {
|
||||
function random(bytes?: number): string;
|
||||
function state(bytes?: number): string;
|
||||
function nonce(bytes?: number): string;
|
||||
function codeVerifier(bytes?: number): string;
|
||||
function codeChallenge(verifier: string): string;
|
||||
}
|
||||
|
||||
export namespace errors {
|
||||
class OPError extends Error {
|
||||
error_description?: string;
|
||||
error?: string;
|
||||
error_uri?: string;
|
||||
state?: string;
|
||||
scope?: string;
|
||||
session_state?: string;
|
||||
response?: { body?: UnknownObject | Buffer } & http.IncomingMessage;
|
||||
|
||||
constructor(
|
||||
params: {
|
||||
error: string;
|
||||
error_description?: string;
|
||||
error_uri?: string;
|
||||
state?: string;
|
||||
scope?: string;
|
||||
session_state?: string;
|
||||
},
|
||||
response?: { body?: UnknownObject | Buffer } & http.IncomingMessage,
|
||||
);
|
||||
}
|
||||
|
||||
class RPError extends Error {
|
||||
jwt?: string;
|
||||
checks?: object;
|
||||
params?: object;
|
||||
body?: object;
|
||||
response?: { body?: UnknownObject | Buffer } & http.IncomingMessage;
|
||||
now?: number;
|
||||
tolerance?: number;
|
||||
nbf?: number;
|
||||
exp?: number;
|
||||
iat?: number;
|
||||
auth_time?: number;
|
||||
|
||||
constructor(...args: Parameters<typeof format>);
|
||||
constructor(options: {
|
||||
message?: string;
|
||||
printf?: Parameters<typeof format>;
|
||||
response?: { body?: UnknownObject | Buffer } & http.IncomingMessage;
|
||||
[key: string]: unknown;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
type KnownKeys<T> = {
|
||||
[K in keyof T]: string extends K ? never : number extends K ? never : K;
|
||||
} extends { [_ in keyof T]: infer U }
|
||||
? {} extends U
|
||||
? never
|
||||
: U
|
||||
: never;
|
||||
type Override<T1, T2> = Omit<T1, keyof Omit<T2, keyof KnownKeys<T2>>> & T2;
|
||||
Reference in New Issue
Block a user