Auto-commit 2026-04-29 16:31

This commit is contained in:
2026-04-29 16:31:27 -04:00
parent e8687bb6b2
commit 0495ee5bd2
19691 changed files with 3272886 additions and 138 deletions

21
node_modules/openid-client/LICENSE.md generated vendored Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

125
node_modules/openid-client/lib/device_flow_handle.js generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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()),
};

View File

@@ -0,0 +1,4 @@
const util = require('util');
const crypto = require('crypto');
module.exports = util.types.isKeyObject || ((obj) => obj && obj instanceof crypto.KeyObject);

View File

@@ -0,0 +1 @@
module.exports = (a) => !!a && a.constructor === Object;

111
node_modules/openid-client/lib/helpers/issuer.js generated vendored Normal file
View 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
View 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
View 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
View 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;
};

View 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
View 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);

View 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
View File

@@ -0,0 +1 @@
module.exports.keystores = new WeakMap();

View 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 [ID.ietfappsawgaccturi], 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 [ID.ietfappsawgwebfinger] 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;

View 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
View 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
View 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
View 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
View 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
View 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
View 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;

View 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.

View File

@@ -0,0 +1,166 @@
# lru cache
A cache object that deletes the least-recently-used items.
[![Build Status](https://travis-ci.org/isaacs/node-lru-cache.svg?branch=master)](https://travis-ci.org/isaacs/node-lru-cache) [![Coverage Status](https://coveralls.io/repos/isaacs/node-lru-cache/badge.svg?service=github)](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

View 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

View 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"
}
}

View 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.

View 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.
[![Build Status](https://travis-ci.org/isaacs/yallist.svg?branch=master)](https://travis-ci.org/isaacs/yallist) [![Coverage Status](https://coveralls.io/repos/isaacs/yallist/badge.svg?service=github)](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.)

View 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
}
}
}

View 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"
}

View 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
View 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
View 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;