Upgrade octokit to v4.1.2

This commit is contained in:
Angela P Wen 2025-02-19 11:13:12 -08:00
parent dbbcbe019d
commit c1745a9831
1214 changed files with 160765 additions and 0 deletions

View file

@ -0,0 +1,22 @@
"on":
push:
branches:
- "*.x"
- main
- beta
name: Release
jobs:
build:
name: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: lts/*
- run: npm ci
- run: npm run build
- run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

View file

@ -0,0 +1,33 @@
name: Test
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize]
jobs:
node:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
- run: npm ci
- run: npm test
deno:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
- uses: denoland/setup-deno@v1
with:
deno-version: v1.x
- run: npm ci
- run: npm run build:default
- run: npm run test:deno

View file

@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at coc@martynus.net. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

21
node_modules/universal-github-app-jwt/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2019 Gregor Martynus
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.

237
node_modules/universal-github-app-jwt/README.md generated vendored Normal file
View file

@ -0,0 +1,237 @@
# universal-github-app-jwt
> Calculate GitHub App bearer tokens for Node, Deno, and modern browsers
[![@latest](https://img.shields.io/npm/v/universal-github-app-jwt)](https://www.npmjs.com/universal-github-app-jwt)
[![Build Status](https://github.com/gr2m/universal-github-app-jwt/workflows/Test/badge.svg)](https://github.com/gr2m/universal-github-app-jwt/actions?query=workflow%3ATest+branch%3Amaster)
## Usage
<table>
<tbody valign=top align=left>
<tr><th>
Browsers
</th><td width=100%>
Load <code>universal-github-app-jwt</code> directly from <a href="https://esm.sh">esm.sh</a>
```html
<script type="module">
import githubAppJwt from "https://esm.sh/universal-github-app-jwt";
</script>
```
</td></tr>
<tr><th>
Node
</th><td>
Install with <code>npm install universal-github-app-jwt</code>
```js
import githubAppJwt from "universal-github-app-jwt";
```
</td></tr>
<tr><th>
Deno
</th><td>
Load <code>universal-github-app-jwt</code> directly from <a href="https://esm.sh">esm.sh</a>, including types.
```js
import githubAppJwt from "https://esm.sh/universal-github-app-jwt";
```
</td></tr>
</tbody>
</table>
```js
const { token, appId, expiration } = await githubAppJwt({
id: APP_ID,
privateKey: PRIVATE_KEY,
});
```
The retrieved `token` can now be used in Authorization request header, e.g. with [`@octokit/request`](https://github.com/octokit/request.js/#readme):
```js
request("GET /app", {
headers: {
authorization: `bearer ${token}`,
},
});
```
For a complete implementation of GitHub App authentication strategies, see [`@octokit/auth-app.js`](https://github.com/octokit/auth-app.js/#readme).
## `githubAppJwt(options)`
<table width="100%">
<thead align=left>
<tr>
<th width=150>
name
</th>
<th width=70>
type
</th>
<th>
description
</th>
</tr>
</thead>
<tbody align=left valign=top>
<tr>
<th>
<code>options.id</code>
</th>
<th>
<code>number | string</code>
</th>
<td>
<strong>Required</strong>. The GitHub App's ID or Client ID. For <code>github.com</code> and GHES 3.14+, it is recommended to use the Client ID.
</td>
</tr>
<tr>
<th>
<code>options.privateKey</code>
</th>
<th>
<code>string</code>
</th>
<td>
<strong>Required</strong>. Content of the <code>*.pem</code> file you downloaded from the apps about page. You can generate a new private key if needed. Make sure to preserve the line breaks. If your private key contains escaped newlines (`\\n`), they will be automatically replaced with actual newlines.
</td>
</tr>
<tr>
<th>
<code>options.now</code>
</th>
<th>
<code>number</code>
</th>
<td>
An optional override for the current time in seconds since the UNIX epoch. Defaults to <code>Math.floor(Date.now() / 1000))</code>. This value can be overridden to account for a time skew between the local machine and the authentication server.
</td>
</tr>
</tbody>
</table>
`githubAppJwt(options)` resolves with an object with the following keys
<table width="100%">
<thead align=left>
<tr>
<th width=150>
name
</th>
<th width=70>
type
</th>
<th>
description
</th>
</tr>
</thead>
<tbody align=left valign=top>
<tr>
<th>
<code>token</code>
</th>
<th>
<code>string</code>
</th>
<td>
The JSON Web Token (JWT) to authenticate as the app.
</td>
</tr>
<tr>
<th>
<code>appId</code>
</th>
<th>
<code>number</code>
</th>
<td>
The GitHub App database ID or Client ID passed in <code>options.id</code>.
</td>
</tr>
<tr>
<th>
<code>expiration</code>
</th>
<th>
<code>number</code>
</th>
<td>
Timestamp as UNIX epoch, e.g. <code>1530922170</code>. A Date object can be created using <code>new Date(authentication.expiration)</code>.
</td>
</tr>
</tbody>
</table>
<!-- do not remove this anchor, it's used in error messages -->
<a name="private-key-formats"></a>
## About Private Key formats
When downloading a `private-key.pem` file from GitHub, the format is in `PKCS#1` format. Unfortunately, the WebCrypto API only supports `PKCS#8`.
If you use 1Password to store a private key as an SSH key, it will be transformed to the `OpenSSH` format, which is also not supported by WebCrypto.
You can identify the format based on the the first line
| First Line | Format |
| ------------------------------------- | ------- |
| `-----BEGIN RSA PRIVATE KEY-----` | PKCS#1 |
| `-----BEGIN PRIVATE KEY-----` | PKCS#8 |
| `-----BEGIN OPENSSH PRIVATE KEY-----` | OpenSSH |
### Converting `PKCS#1` to `PKCS#8`
- #### Using an Online Private Key Converter
Convert quickly using the Web interface at https://private-key-converter.vercel.app
- #### Using Node.js
If you use Node.js, you can convert the format before passing it to `universal-github-app-jwt`:
```js
import crypto from "node:crypto";
import githubAppJwt from "universal-github-app-jwt";
const privateKeyPkcs8 = crypto
.createPrivateKey(process.env.PRIVATE_KEY)
.export({
type: "pkcs8",
format: "pem",
});
const { token, appId, expiration } = await githubAppJwt({
id: process.env.APP_ID,
privateKey: privateKeyPkcs8,
});
```
- #### Using OpenSSL
Convert the format using `openssl` before passing it to your app.
```
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private-key.pem -out private-key-pkcs8.key
```
### Converting `OpenSSH` to `PKCS#8`
```
cp private-key.pem private-key-pkcs8.key && ssh-keygen -m PKCS8 -N "" -f private-key-pkcs8.key
```
I'm looking for help to create a minimal `OpenSSH` to `PKCS` convert library that I can recommend people to use before passing the private key to `githubAppJwt`. Please create an issue if you'd like to help.
## License
[MIT](LICENSE)

13
node_modules/universal-github-app-jwt/index.d.ts generated vendored Normal file
View file

@ -0,0 +1,13 @@
export type Options<IdType extends number | string = number> = {
id: IdType;
privateKey: string;
now?: number;
};
export type Result<IdType extends number | string = number> = {
appId: IdType extends string ? string : number;
expiration: number;
token: string;
};
export default function githubAppJwt<T extends number | string = number>(options: Options<T>): Promise<Result<T>>;

42
node_modules/universal-github-app-jwt/index.js generated vendored Normal file
View file

@ -0,0 +1,42 @@
// @ts-check
// @ts-ignore - #get-token is defined in "imports" in package.json
import { getToken } from "./lib/get-token.js";
/**
* @param {import(".").Options} options
* @returns {Promise<import(".").Result>}
*/
export default async function githubAppJwt({
id,
privateKey,
now = Math.floor(Date.now() / 1000),
}) {
// Private keys are often times configured as environment variables, in which case line breaks are escaped using `\\n`.
// Replace these here for convenience.
const privateKeyWithNewlines = privateKey.replace(/\\n/g, '\n');
// When creating a JSON Web Token, it sets the "issued at time" (iat) to 30s
// in the past as we have seen people running situations where the GitHub API
// claimed the iat would be in future. It turned out the clocks on the
// different machine were not in sync.
const nowWithSafetyMargin = now - 30;
const expiration = nowWithSafetyMargin + 60 * 10; // JWT expiration time (10 minute maximum)
const payload = {
iat: nowWithSafetyMargin, // Issued at time
exp: expiration,
iss: id,
};
const token = await getToken({
privateKey: privateKeyWithNewlines,
payload,
});
return {
appId: id,
expiration,
token,
};
}

25
node_modules/universal-github-app-jwt/index.test-d.ts generated vendored Normal file
View file

@ -0,0 +1,25 @@
import { expectType } from "tsd";
import githubAppJwt from ".";
export async function test() {
const result = await githubAppJwt({
id: 123,
privateKey: "",
});
expectType<number>(result.appId);
expectType<number>(result.expiration);
expectType<string>(result.token);
}
// Test case to verify `id` can be set to a string
export async function testWithStringId() {
const resultWithStringId = await githubAppJwt({
id: "client_id_string",
privateKey: "",
});
expectType<string>(resultWithStringId.appId);
expectType<number>(resultWithStringId.expiration);
expectType<string>(resultWithStringId.token);
}

16
node_modules/universal-github-app-jwt/internals.d.ts generated vendored Normal file
View file

@ -0,0 +1,16 @@
export type Payload = {
iat: number;
exp: number;
iss: number | string;
};
export type Header = { alg: "RS256"; typ: "JWT" };
export type GetTokenOptions = {
privateKey: string;
payload: Payload;
};
export interface GetToken {
(options: GetTokenOptions): Promise<string>;
}

5
node_modules/universal-github-app-jwt/jsconfig.json generated vendored Normal file
View file

@ -0,0 +1,5 @@
{
"compilerOptions": {
"strictNullChecks": true
}
}

View file

@ -0,0 +1,8 @@
const { subtle } = globalThis.crypto;
// no-op, unfortunately there is no way to transform from PKCS8 or OpenSSH to PKCS1 with WebCrypto
function convertPrivateKey(privateKey) {
return privateKey;
}
export { subtle, convertPrivateKey };

View file

@ -0,0 +1,15 @@
// this can be removed once we only support Node 20+
export * from "node:crypto";
import { createPrivateKey } from "node:crypto";
import { isPkcs1 } from "./utils.js";
// no-op, unfortunately there is no way to transform from PKCS8 or OpenSSH to PKCS1 with WebCrypto
export function convertPrivateKey(privateKey) {
if (!isPkcs1(privateKey)) return privateKey;
return createPrivateKey(privateKey).export({
type: "pkcs8",
format: "pem",
});
}

66
node_modules/universal-github-app-jwt/lib/get-token.js generated vendored Normal file
View file

@ -0,0 +1,66 @@
// we don't @ts-check here because it chokes crypto which is a global API in modern JS runtime environments
import {
isPkcs1,
isOpenSsh,
getEncodedMessage,
getDERfromPEM,
string2ArrayBuffer,
base64encode,
} from "./utils.js";
import { subtle, convertPrivateKey } from "#crypto";
/**
* @param {import('../internals').GetTokenOptions} options
* @returns {Promise<string>}
*/
export async function getToken({ privateKey, payload }) {
const convertedPrivateKey = convertPrivateKey(privateKey);
// WebCrypto only supports PKCS#8, unfortunately
/* c8 ignore start */
if (isPkcs1(convertedPrivateKey)) {
throw new Error(
"[universal-github-app-jwt] Private Key is in PKCS#1 format, but only PKCS#8 is supported. See https://github.com/gr2m/universal-github-app-jwt#private-key-formats"
);
}
/* c8 ignore stop */
// WebCrypto does not support OpenSSH, unfortunately
if (isOpenSsh(convertedPrivateKey)) {
throw new Error(
"[universal-github-app-jwt] Private Key is in OpenSSH format, but only PKCS#8 is supported. See https://github.com/gr2m/universal-github-app-jwt#private-key-formats"
);
}
const algorithm = {
name: "RSASSA-PKCS1-v1_5",
hash: { name: "SHA-256" },
};
/** @type {import('../internals').Header} */
const header = { alg: "RS256", typ: "JWT" };
const privateKeyDER = getDERfromPEM(convertedPrivateKey);
const importedKey = await subtle.importKey(
"pkcs8",
privateKeyDER,
algorithm,
false,
["sign"]
);
const encodedMessage = getEncodedMessage(header, payload);
const encodedMessageArrBuf = string2ArrayBuffer(encodedMessage);
const signatureArrBuf = await subtle.sign(
algorithm.name,
importedKey,
encodedMessageArrBuf
);
const encodedSignature = base64encode(signatureArrBuf);
return `${encodedMessage}.${encodedSignature}`;
}

85
node_modules/universal-github-app-jwt/lib/utils.js generated vendored Normal file
View file

@ -0,0 +1,85 @@
// we don't @ts-check here because it chokes on atob and btoa which are available in all modern JS runtime environments
/**
* @param {string} privateKey
* @returns {boolean}
*/
export function isPkcs1(privateKey) {
return privateKey.includes("-----BEGIN RSA PRIVATE KEY-----");
}
/**
* @param {string} privateKey
* @returns {boolean}
*/
export function isOpenSsh(privateKey) {
return privateKey.includes("-----BEGIN OPENSSH PRIVATE KEY-----");
}
/**
* @param {string} str
* @returns {ArrayBuffer}
*/
export function string2ArrayBuffer(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
/**
* @param {string} pem
* @returns {ArrayBuffer}
*/
export function getDERfromPEM(pem) {
const pemB64 = pem
.trim()
.split("\n")
.slice(1, -1) // Remove the --- BEGIN / END PRIVATE KEY ---
.join("");
const decoded = atob(pemB64);
return string2ArrayBuffer(decoded);
}
/**
* @param {import('../internals').Header} header
* @param {import('../internals').Payload} payload
* @returns {string}
*/
export function getEncodedMessage(header, payload) {
return `${base64encodeJSON(header)}.${base64encodeJSON(payload)}`;
}
/**
* @param {ArrayBuffer} buffer
* @returns {string}
*/
export function base64encode(buffer) {
var binary = "";
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return fromBase64(btoa(binary));
}
/**
* @param {string} base64
* @returns {string}
*/
function fromBase64(base64) {
return base64.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
}
/**
* @param {Record<string,unknown>} obj
* @returns {string}
*/
function base64encodeJSON(obj) {
return fromBase64(btoa(JSON.stringify(obj)));
}

62
node_modules/universal-github-app-jwt/package.json generated vendored Normal file
View file

@ -0,0 +1,62 @@
{
"name": "universal-github-app-jwt",
"type": "module",
"version": "2.2.0",
"exports": "./index.js",
"imports": {
"#crypto": {
"node": "./lib/crypto-node.js",
"default": "./lib/crypto-native.js"
}
},
"description": "Calculate GitHub App bearer tokens for Node & modern browsers",
"repository": "github:gr2m/universal-github-app-jwt",
"keywords": [
"github",
"authentication",
"app",
"jwt",
"webcrypto"
],
"author": "Gregor Martynus (https://github.com/gr2m)",
"scripts": {
"test": "npm run test:code && npm run test:tsc && npm run test:tsd && npm run lint",
"test:code": "c8 --100 ava test/node.test.js",
"test:deno": "deno test test/deno.test.js",
"test:tsc": "tsc --allowJs --noEmit --esModuleInterop --skipLibCheck --lib es2020 index.js",
"test:tsd": "tsd",
"lint": "prettier --check '{src,test}/**/*' README.md package.json",
"lint:fix": "prettier --write '{src,test}/**/*' README.md package.json",
"coverage": "c8 report --reporter html",
"postcoverage": "open-cli coverage/index.html",
"build": "npm run build:default && npm run build:node",
"build:default": "esbuild index.js --bundle --outfile=dist/default.js --platform=browser --target=es2020 --format=esm",
"build:node": "esbuild index.js --bundle --outfile=dist/node.js --platform=node --target=es2020 --format=esm"
},
"license": "MIT",
"devDependencies": {
"ava": "^6.0.0",
"c8": "^9.0.0",
"esbuild": "^0.20.0",
"mockdate": "^3.0.5",
"open-cli": "^8.0.0",
"prettier": "^3.0.0",
"tsd": "^0.31.0",
"typescript": "^5.0.0"
},
"release": {
"branches": [
"+([0-9]).x",
"main",
{
"name": "beta",
"prerelease": true
}
]
},
"renovate": {
"extends": [
"github>gr2m/.github"
]
}
}

View file

@ -0,0 +1,49 @@
import githubAppJwt from "../dist/default.js";
const APP_ID = 1;
const PRIVATE_KEY = `-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDVzv73Pk9p3s56
N5yxDRu7dqjM3e2KE+aWOee51v0bccQJ2ceVa7b9rWAH0lblMFD4BWm6b06THsp+
qR8Eov2ZweBIvTJYx2Mx806o22tCoqU3iQSnpEP77uwZvNt9n1qvCuUP8dIMBYZ0
YYlNI4Ezqkd6HIuZILcMmhH8JO7S9MZNZdCs7rhny3JdA+1U9v9hetxSFsGnyLvZ
v1eTLR8Po+QR5s7LQinnxdUCfZQ82U05I9LJ75CO2K6zQx3g2J7j5fyTBUjZCOTd
1KbSzD/vbQomR1UOatrJ6WO0oHHoC01CxJeDNBt4yaKoUWTCsbX7PHoTsfuOohD0
Hpu9YpcbAgMBAAECggEAPyQEE8vo8+ECpQErWvX+DJx8ORQJBE/gNtke37jnwmUU
ebxAvpWy0rOSunyZgNGF99jRYmdgkv3y2vji2iGwNuoUbCbDaYhoeOXbgu5ZfLI/
jGkAYOmX0hy6yNcHEtAunabgApdtanNvQ4tSWt9zVmig9yTa7PvGUwhk60uU4+Mv
PYO56NV7bglzDAfOtBYo58DXVH/17nQNWx6GdIf/DjpDvrfLgjQTcEihQyyiUQrO
HbJ0ADLOSBpsZAFS5qZmi01+8mgNd4KLUsPzI0JbJOViklkkMNeigFTkQCwK+E3W
xJGhpdauUxIMHuv8T5pDIq5rgo42q+agm4LbW9Ip4QKBgQDvJbrAGRWg2GBeeTxd
Jm/db5DTG11WmJ0l40YFadzOVmu6aa3jHDfGzrNX6sZQPLn3IOQrAEqMwxrjYyeL
tP0XHz4QpS6FUrc9VDJqOjJCoXBPUY5Ek3Nz95hDpVg4JILw7JmawEzan7QPgUXb
9pvBI8ybLQ2DIUsJQVVzc4QKmQKBgQDk4CYjfC3mz5yWDXypLsEpHYO44VavM1Vw
dheGPHy85JZXTfc7LfK91QECG70DUtSqnDIxr66ciDGa+ZQxAR3IdAxyAGxWzXR1
H+DbEaMwtzCPqSf7GvclUhmdtFPnRi4+F/6ezVJx2E/q6mj0jT+xGwi433oZvrkk
nH3iBDiT0wKBgE7lXqADZoxC9kAUtSJyDNO7+8Z5r6hi/u1B9pbQnwT/o9jDBpf3
djtDdA1cKgLMlfl+w2egV/fqYhOEYcaIdjrLltk89YUMjeFQxrUe7/fldLzmRg4/
qwYmN/iRMvKKsRw0olRYfsJdj7TRzC9OQ4JLgjPrgBqzwCKUiFFnWbd5AoGBAJRb
Wz1rNBHGB5kYWvMLdHfjQsvnfRoJ61r/oVYJBU4n2e/zgMtiiFNWq9WjB00NNv70
SnD8kPG0MntjRhTRxW13E84dyhwmB1QYetdlwmNEi3zDyD+zhfoyEpqwFib2zejA
AvMK4mMbNQpwMeI7YMq7XFcBvRLNFxPNQKft1oKzAoGBAM5g9nYkaaGJuoqOMsWb
SrOlxDpE+88rX/uDQ0ieaM8x5s/Qrp5I/HT3/j0npZMP74RqM3sWGS1RJjG6R1Zo
KhwBAlMM1g/Qrzwbiu0LYhjLkkWf1JbPmiHH//S77N39H9BFTMs7Dg3vb8e75Qbo
w23mINkUK1qlFoq3o69IHDLz
-----END PRIVATE KEY-----`;
// see https://runkit.com/gr2m/reproducable-jwt
const BEARER =
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOi0zMCwiZXhwIjo1NzAsImlzcyI6MX0.q3foRa78U3WegM5PrWLEh5N0bH1SD62OqW66ZYzArp95JBNiCbo8KAlGtiRENCIfBZT9ibDUWy82cI4g3F09mdTq3bD1xLavIfmTksIQCz5EymTWR5v6gL14LSmQdWY9lSqkgUG0XCFljWUglEP39H4yeHbFgdjvAYg3ifDS12z9oQz2ACdSpvxPiTuCC804HkPVw8Qoy0OSXvCkFU70l7VXCVUxnuhHnk8-oCGcKUspmeP6UdDnXk-Aus-eGwDfJbU2WritxxaXw6B4a3flTPojkYLSkPBr6Pi0H2-mBsW_Nvs0aLPVLKobQd4gqTkosX3967DoAG8luUMhrnxe8Q";
// url_test.ts
import { assertEquals } from "https://deno.land/std@0.168.0/testing/asserts.ts";
Deno.test("url test", async () => {
const result = await githubAppJwt({
id: APP_ID,
privateKey: PRIVATE_KEY,
now: 0,
});
assertEquals(result.appId, 1);
assertEquals(result.expiration, 570);
assertEquals(result.token, BEARER);
});

192
node_modules/universal-github-app-jwt/test/node.test.js generated vendored Normal file
View file

@ -0,0 +1,192 @@
import test from "ava";
import MockDate from "mockdate";
import githubAppJwt from "../index.js";
const APP_ID = 1;
// private key in pkcs1 format, as it's provided by GitHub
const PRIVATE_KEY_PKCS1 = `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1c7+9z5Pad7OejecsQ0bu3aozN3tihPmljnnudb9G3HECdnH
lWu2/a1gB9JW5TBQ+AVpum9Okx7KfqkfBKL9mcHgSL0yWMdjMfNOqNtrQqKlN4kE
p6RD++7sGbzbfZ9arwrlD/HSDAWGdGGJTSOBM6pHehyLmSC3DJoR/CTu0vTGTWXQ
rO64Z8tyXQPtVPb/YXrcUhbBp8i72b9Xky0fD6PkEebOy0Ip58XVAn2UPNlNOSPS
ye+Qjtius0Md4Nie4+X8kwVI2Qjk3dSm0sw/720KJkdVDmrayeljtKBx6AtNQsSX
gzQbeMmiqFFkwrG1+zx6E7H7jqIQ9B6bvWKXGwIDAQABAoIBAD8kBBPL6PPhAqUB
K1r1/gycfDkUCQRP4DbZHt+458JlFHm8QL6VstKzkrp8mYDRhffY0WJnYJL98tr4
4tohsDbqFGwmw2mIaHjl24LuWXyyP4xpAGDpl9IcusjXBxLQLp2m4AKXbWpzb0OL
Ulrfc1ZooPck2uz7xlMIZOtLlOPjLz2DuejVe24JcwwHzrQWKOfA11R/9e50DVse
hnSH/w46Q763y4I0E3BIoUMsolEKzh2ydAAyzkgabGQBUuamZotNfvJoDXeCi1LD
8yNCWyTlYpJZJDDXooBU5EAsCvhN1sSRoaXWrlMSDB7r/E+aQyKua4KONqvmoJuC
21vSKeECgYEA7yW6wBkVoNhgXnk8XSZv3W+Q0xtdVpidJeNGBWnczlZrummt4xw3
xs6zV+rGUDy59yDkKwBKjMMa42Mni7T9Fx8+EKUuhVK3PVQyajoyQqFwT1GORJNz
c/eYQ6VYOCSC8OyZmsBM2p+0D4FF2/abwSPMmy0NgyFLCUFVc3OECpkCgYEA5OAm
I3wt5s+clg18qS7BKR2DuOFWrzNVcHYXhjx8vOSWV033Oy3yvdUBAhu9A1LUqpwy
Ma+unIgxmvmUMQEdyHQMcgBsVs10dR/g2xGjMLcwj6kn+xr3JVIZnbRT50YuPhf+
ns1ScdhP6upo9I0/sRsIuN96Gb65JJx94gQ4k9MCgYBO5V6gA2aMQvZAFLUicgzT
u/vGea+oYv7tQfaW0J8E/6PYwwaX93Y7Q3QNXCoCzJX5fsNnoFf36mIThGHGiHY6
y5bZPPWFDI3hUMa1Hu/35XS85kYOP6sGJjf4kTLyirEcNKJUWH7CXY+00cwvTkOC
S4Iz64Aas8AilIhRZ1m3eQKBgQCUW1s9azQRxgeZGFrzC3R340LL530aCeta/6FW
CQVOJ9nv84DLYohTVqvVowdNDTb+9Epw/JDxtDJ7Y0YU0cVtdxPOHcocJgdUGHrX
ZcJjRIt8w8g/s4X6MhKasBYm9s3owALzCuJjGzUKcDHiO2DKu1xXAb0SzRcTzUCn
7daCswKBgQDOYPZ2JGmhibqKjjLFm0qzpcQ6RPvPK1/7g0NInmjPMebP0K6eSPx0
9/49J6WTD++EajN7FhktUSYxukdWaCocAQJTDNYP0K88G4rtC2IYy5JFn9SWz5oh
x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w==
-----END RSA PRIVATE KEY-----`;
// pkcs8 version of the key above, which is pkcs1
// see https://stackoverflow.com/questions/51033786/how-can-i-import-an-rsa-private-key-in-pem-format-for-use-with-webcrypto/51035703#51035703
const PRIVATE_KEY_PKCS8 = `-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDVzv73Pk9p3s56
N5yxDRu7dqjM3e2KE+aWOee51v0bccQJ2ceVa7b9rWAH0lblMFD4BWm6b06THsp+
qR8Eov2ZweBIvTJYx2Mx806o22tCoqU3iQSnpEP77uwZvNt9n1qvCuUP8dIMBYZ0
YYlNI4Ezqkd6HIuZILcMmhH8JO7S9MZNZdCs7rhny3JdA+1U9v9hetxSFsGnyLvZ
v1eTLR8Po+QR5s7LQinnxdUCfZQ82U05I9LJ75CO2K6zQx3g2J7j5fyTBUjZCOTd
1KbSzD/vbQomR1UOatrJ6WO0oHHoC01CxJeDNBt4yaKoUWTCsbX7PHoTsfuOohD0
Hpu9YpcbAgMBAAECggEAPyQEE8vo8+ECpQErWvX+DJx8ORQJBE/gNtke37jnwmUU
ebxAvpWy0rOSunyZgNGF99jRYmdgkv3y2vji2iGwNuoUbCbDaYhoeOXbgu5ZfLI/
jGkAYOmX0hy6yNcHEtAunabgApdtanNvQ4tSWt9zVmig9yTa7PvGUwhk60uU4+Mv
PYO56NV7bglzDAfOtBYo58DXVH/17nQNWx6GdIf/DjpDvrfLgjQTcEihQyyiUQrO
HbJ0ADLOSBpsZAFS5qZmi01+8mgNd4KLUsPzI0JbJOViklkkMNeigFTkQCwK+E3W
xJGhpdauUxIMHuv8T5pDIq5rgo42q+agm4LbW9Ip4QKBgQDvJbrAGRWg2GBeeTxd
Jm/db5DTG11WmJ0l40YFadzOVmu6aa3jHDfGzrNX6sZQPLn3IOQrAEqMwxrjYyeL
tP0XHz4QpS6FUrc9VDJqOjJCoXBPUY5Ek3Nz95hDpVg4JILw7JmawEzan7QPgUXb
9pvBI8ybLQ2DIUsJQVVzc4QKmQKBgQDk4CYjfC3mz5yWDXypLsEpHYO44VavM1Vw
dheGPHy85JZXTfc7LfK91QECG70DUtSqnDIxr66ciDGa+ZQxAR3IdAxyAGxWzXR1
H+DbEaMwtzCPqSf7GvclUhmdtFPnRi4+F/6ezVJx2E/q6mj0jT+xGwi433oZvrkk
nH3iBDiT0wKBgE7lXqADZoxC9kAUtSJyDNO7+8Z5r6hi/u1B9pbQnwT/o9jDBpf3
djtDdA1cKgLMlfl+w2egV/fqYhOEYcaIdjrLltk89YUMjeFQxrUe7/fldLzmRg4/
qwYmN/iRMvKKsRw0olRYfsJdj7TRzC9OQ4JLgjPrgBqzwCKUiFFnWbd5AoGBAJRb
Wz1rNBHGB5kYWvMLdHfjQsvnfRoJ61r/oVYJBU4n2e/zgMtiiFNWq9WjB00NNv70
SnD8kPG0MntjRhTRxW13E84dyhwmB1QYetdlwmNEi3zDyD+zhfoyEpqwFib2zejA
AvMK4mMbNQpwMeI7YMq7XFcBvRLNFxPNQKft1oKzAoGBAM5g9nYkaaGJuoqOMsWb
SrOlxDpE+88rX/uDQ0ieaM8x5s/Qrp5I/HT3/j0npZMP74RqM3sWGS1RJjG6R1Zo
KhwBAlMM1g/Qrzwbiu0LYhjLkkWf1JbPmiHH//S77N39H9BFTMs7Dg3vb8e75Qbo
w23mINkUK1qlFoq3o69IHDLz
-----END PRIVATE KEY-----`;
// openssh version of the key above
// see https://github.com/gr2m/universal-github-app-jwt/issues/72
const PRIVATEY_KEY_OPENSSH = `-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEA1c7+9z5Pad7OejecsQ0bu3aozN3tihPmljnnudb9G3HECdnHlWu2
/a1gB9JW5TBQ+AVpum9Okx7KfqkfBKL9mcHgSL0yWMdjMfNOqNtrQqKlN4kEp6RD++7sGb
zbfZ9arwrlD/HSDAWGdGGJTSOBM6pHehyLmSC3DJoR/CTu0vTGTWXQrO64Z8tyXQPtVPb/
YXrcUhbBp8i72b9Xky0fD6PkEebOy0Ip58XVAn2UPNlNOSPSye+Qjtius0Md4Nie4+X8kw
VI2Qjk3dSm0sw/720KJkdVDmrayeljtKBx6AtNQsSXgzQbeMmiqFFkwrG1+zx6E7H7jqIQ
9B6bvWKXGwAAA7hJqTyJSak8iQAAAAdzc2gtcnNhAAABAQDVzv73Pk9p3s56N5yxDRu7dq
jM3e2KE+aWOee51v0bccQJ2ceVa7b9rWAH0lblMFD4BWm6b06THsp+qR8Eov2ZweBIvTJY
x2Mx806o22tCoqU3iQSnpEP77uwZvNt9n1qvCuUP8dIMBYZ0YYlNI4Ezqkd6HIuZILcMmh
H8JO7S9MZNZdCs7rhny3JdA+1U9v9hetxSFsGnyLvZv1eTLR8Po+QR5s7LQinnxdUCfZQ8
2U05I9LJ75CO2K6zQx3g2J7j5fyTBUjZCOTd1KbSzD/vbQomR1UOatrJ6WO0oHHoC01CxJ
eDNBt4yaKoUWTCsbX7PHoTsfuOohD0Hpu9YpcbAAAAAwEAAQAAAQA/JAQTy+jz4QKlASta
9f4MnHw5FAkET+A22R7fuOfCZRR5vEC+lbLSs5K6fJmA0YX32NFiZ2CS/fLa+OLaIbA26h
RsJsNpiGh45duC7ll8sj+MaQBg6ZfSHLrI1wcS0C6dpuACl21qc29Di1Ja33NWaKD3JNrs
+8ZTCGTrS5Tj4y89g7no1XtuCXMMB860FijnwNdUf/XudA1bHoZ0h/8OOkO+t8uCNBNwSK
FDLKJRCs4dsnQAMs5IGmxkAVLmpmaLTX7yaA13gotSw/MjQlsk5WKSWSQw16KAVORALAr4
TdbEkaGl1q5TEgwe6/xPmkMirmuCjjar5qCbgttb0inhAAAAgQDOYPZ2JGmhibqKjjLFm0
qzpcQ6RPvPK1/7g0NInmjPMebP0K6eSPx09/49J6WTD++EajN7FhktUSYxukdWaCocAQJT
DNYP0K88G4rtC2IYy5JFn9SWz5ohx//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapR
aKt6OvSBwy8wAAAIEA7yW6wBkVoNhgXnk8XSZv3W+Q0xtdVpidJeNGBWnczlZrummt4xw3
xs6zV+rGUDy59yDkKwBKjMMa42Mni7T9Fx8+EKUuhVK3PVQyajoyQqFwT1GORJNzc/eYQ6
VYOCSC8OyZmsBM2p+0D4FF2/abwSPMmy0NgyFLCUFVc3OECpkAAACBAOTgJiN8LebPnJYN
fKkuwSkdg7jhVq8zVXB2F4Y8fLzklldN9zst8r3VAQIbvQNS1KqcMjGvrpyIMZr5lDEBHc
h0DHIAbFbNdHUf4NsRozC3MI+pJ/sa9yVSGZ20U+dGLj4X/p7NUnHYT+rqaPSNP7EbCLjf
ehm+uSScfeIEOJPTAAAAAAEC
-----END OPENSSH PRIVATE KEY-----`;
// see https://runkit.com/gr2m/reproducable-jwt
const BEARER =
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOi0zMCwiZXhwIjo1NzAsImlzcyI6MX0.q3foRa78U3WegM5PrWLEh5N0bH1SD62OqW66ZYzArp95JBNiCbo8KAlGtiRENCIfBZT9ibDUWy82cI4g3F09mdTq3bD1xLavIfmTksIQCz5EymTWR5v6gL14LSmQdWY9lSqkgUG0XCFljWUglEP39H4yeHbFgdjvAYg3ifDS12z9oQz2ACdSpvxPiTuCC804HkPVw8Qoy0OSXvCkFU70l7VXCVUxnuhHnk8-oCGcKUspmeP6UdDnXk-Aus-eGwDfJbU2WritxxaXw6B4a3flTPojkYLSkPBr6Pi0H2-mBsW_Nvs0aLPVLKobQd4gqTkosX3967DoAG8luUMhrnxe8Q";
test("README example for app auth with private key in PKCS#8 format", async (t) => {
MockDate.set(0);
const result = await githubAppJwt({
id: APP_ID,
privateKey: PRIVATE_KEY_PKCS8,
});
t.deepEqual(result, {
appId: APP_ID,
expiration: 570,
token: BEARER,
});
});
test("README example for app auth with private key in PKCS#1 format", async (t) => {
MockDate.set(0);
const result = await githubAppJwt({
id: APP_ID,
privateKey: PRIVATE_KEY_PKCS1,
});
t.deepEqual(result, {
appId: APP_ID,
expiration: 570,
token: BEARER,
});
});
test("Throws error if key is OpenSSH", async (t) => {
MockDate.set(0);
try {
await githubAppJwt({
id: APP_ID,
privateKey: PRIVATEY_KEY_OPENSSH,
});
t.fail("should throw");
} catch (error) {
t.is(
error.message,
"[universal-github-app-jwt] Private Key is in OpenSSH format, but only PKCS#8 is supported. See https://github.com/gr2m/universal-github-app-jwt#private-key-formats",
);
}
});
test("Include the time difference in the expiration and issued_at field", async (t) => {
MockDate.set(0);
const result = await githubAppJwt({
id: APP_ID,
privateKey: PRIVATE_KEY_PKCS8,
now: 10,
});
t.is(result.appId, APP_ID);
t.is(result.expiration, 580);
const resultPayload = JSON.parse(atob(result.token.split(".")[1]));
t.is(resultPayload.exp, 580);
t.is(resultPayload.iat, -20);
});
test("Replace escaped line breaks with actual linebreaks", async (t) => {
MockDate.set(0);
const result = await githubAppJwt({
id: APP_ID,
privateKey: PRIVATE_KEY_PKCS8.replace(/\n/g, "\\n"),
});
t.deepEqual(result, {
appId: APP_ID,
expiration: 570,
token: BEARER,
});
});
// New test for id set to Client ID
test("id set to Client ID", async (t) => {
MockDate.set(0);
const result = await githubAppJwt({
id: "client_id_string",
privateKey: PRIVATE_KEY_PKCS8,
});
t.is(typeof result.token, "string");
t.is(result.appId, "client_id_string");
});