diff --git a/test/integration/apps-test.js b/test/integration/apps-test.js index fda36a9c..5e080df2 100644 --- a/test/integration/apps-test.js +++ b/test/integration/apps-test.js @@ -1,6 +1,8 @@ const nock = require("nock"); const Octokit = require("../../"); +const BEARER_TOKEN = + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw"; require("../mocha-node-setup"); @@ -10,56 +12,38 @@ describe("apps", () => { beforeEach(() => { octokit = new Octokit({ baseUrl: "https://apps-test-host.com", - auth: "Bearer 123" + auth: `Bearer ${BEARER_TOKEN}`, + log: console.log }); }); it('adds "machine-man" preview header', () => { nock("https://apps-test-host.com", { reqheaders: { - authorization: "Bearer 123", - accept: - "application/vnd.github.v3+json,application/vnd.github.machine-man-preview+json" - } - }) - .get("/orgs/myorg") - .reply(200, {}); - - return octokit.orgs.get({ org: "myorg" }); - }); - - it('adds "machine-man" preview header to custom accept header', () => { - nock("https://apps-test-host.com", { - reqheaders: { - authorization: "Bearer 123", - accept: "foo-bar,application/vnd.github.machine-man-preview+json" + authorization: `bearer ${BEARER_TOKEN}`, + accept: "application/vnd.github.machine-man-preview+json" } }) - .get("/orgs/myorg") + .get("/app") .reply(200, {}); - return octokit.orgs.get({ - org: "myorg", - headers: { - accept: "foo-bar" - } - }); + return octokit.apps.getAuthenticated(); }); - it('does not add "machine-man" preview header if it is already set', () => { + it('adds "machine-man" preview header to custom media type', () => { nock("https://apps-test-host.com", { reqheaders: { - authorization: "Bearer 123", - accept: "application/vnd.github.machine-man-preview+json" + authorization: `bearer ${BEARER_TOKEN}`, + accept: + "application/vnd.github.machine-man-preview+json,application/vnd.github.foo-bar-preview+json" } }) - .get("/orgs/myorg") + .get("/app") .reply(200, {}); - return octokit.orgs.get({ - org: "myorg", - headers: { - accept: "application/vnd.github.machine-man-preview+json" + return octokit.apps.getAuthenticated({ + mediaType: { + previews: ["foo-bar"] } }); }); diff --git a/test/integration/authentication-test.js b/test/integration/authentication-test.js new file mode 100644 index 00000000..aeeaaa9c --- /dev/null +++ b/test/integration/authentication-test.js @@ -0,0 +1,152 @@ +const nock = require("nock"); +const { createActionAuth } = require("@octokit/auth"); + +const Octokit = require("../.."); + +require("../mocha-node-setup"); + +describe("authentication", () => { + it("unauthenticated", () => { + nock("https://authentication-test-host.com") + .get("/") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com" + }); + + return octokit.auth().then(authentication => { + expect(authentication).to.deep.equal({ + type: "unauthenticated" + }); + }); + }); + + it("OAuth token string", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "token abc4567" + } + }) + .get("/") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: "token abc4567" + }); + + return octokit.request("/"); + }); + + const BEARER_TOKEN = + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw"; + it("JSON Web Token string (app authentication)", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: `bearer ${BEARER_TOKEN}` + } + }) + .get("/") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: `bearer ${BEARER_TOKEN}` + }); + + return octokit.request("/"); + }); + + it("error to authenticated request", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "token abc4567" + } + }) + .get("/") + .reply(404, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: "token abc4567", + log: { + warn() {} + } + }); + + return octokit + .request("/") + + .catch(() => {}); + }); + + it("options.auth=token without prefix", () => { + nock("https://authentication-test-host-token-without-prefix.com", { + reqheaders: { + authorization: "token abc4567" + } + }) + .get("/") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host-token-without-prefix.com", + auth: "abc4567" + }); + + return octokit.request("/").catch(error => { + console.log(`error.request`); + console.log(error.request); + }); + }); + + it("options.auth=bearer without prefix", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: + "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw" + } + }) + .get("/app") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw" + }); + + return octokit.request("/app"); + }); + + it("invalid auth errors", () => { + expect(() => { + Octokit({ auth: {}, log: { warn() {} } }); + }).to.throw(Error); + }); + + it("auth = createActionAuth()", async () => { + nock("https://api.github.com", { + reqheaders: { + authorization: `token githubtoken123` + } + }) + .get("/") + .reply(200, {}); + + const currentEnv = process.env; + process.env = { + GITHUB_ACTION: "1", + GITHUB_TOKEN: "githubtoken123" + }; + + const octokit = new Octokit({ + authStrategy: createActionAuth + }); + + return octokit.request("/").then(() => { + process.env = currentEnv; + }); + }); +}); diff --git a/test/integration/deprecated-authentication-test.js b/test/integration/deprecated-authentication-test.js deleted file mode 100644 index 0f3b438b..00000000 --- a/test/integration/deprecated-authentication-test.js +++ /dev/null @@ -1,568 +0,0 @@ -const nock = require("nock"); -const btoa = require("btoa-lite"); - -const Octokit = require("../.."); - -require("../mocha-node-setup"); - -describe("authentication", () => { - it("token", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "token abc4567" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: "token abc4567" - }); - - return octokit.request("/"); - }); - - it("basic", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password" - } - }); - - return octokit.request("/"); - }); - - it("basic with 2fa", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" - } - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app" - } - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - on2fa() { - return 123456; - } - } - }); - - return octokit.request("/"); - }); - - it("basic with async 2fa", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" - } - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app" - } - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - on2fa() { - return Promise.resolve(123456); - } - } - }); - - return octokit.request("/"); - }); - - it("basic with 2fa and invalid one-time-password", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" - } - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app" - } - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456" - } - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app" - } - ); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - on2fa() { - return 123456; - } - } - }); - - return octokit - .request("/") - - .then(() => { - throw new Error("should not resolve"); - }) - - .catch(error => { - expect(error.message).to.match(/Invalid one-time password/i); - }); - }); - - it("basic with expiring 2fa", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" - } - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app" - } - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "1" - } - }) - .get("/") - .reply(200, {}); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "1" - } - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app" - } - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "2" - } - }) - .get("/") - .reply(200, {}); - - let callCount = 0; - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - on2fa() { - return ++callCount; - } - } - }); - - return octokit - .request("/") - .then(() => octokit.request("/")) - .then(() => { - expect(callCount).to.equal(2); - }); - }); - - it("basic with missing 2fa", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" - } - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app" - } - ); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password" - } - }); - - return octokit - .request("/") - - .then(() => { - throw new Error('should fail with "on2fa missing" error'); - }) - - .catch(error => { - expect(error.message).to.equal( - "2FA required, but options.on2fa is not a function. See https://github.com/octokit/rest.js#authentication" - ); - expect(error.status).to.equal(401); - expect(!!error.headers).to.equal(true); - expect(!!error.request).to.equal(true); - }); - }); - - it("app", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Bearer abc4567" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: "Bearer abc4567" - }); - - return octokit.request("/"); - }); - - it("oauth key & secret", () => { - nock("https://authentication-test-host.com") - .get("/") - .query({ client_id: "id123", client_secret: "secret456" }) - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - clientId: "id123", - clientSecret: "secret456" - } - }); - - return octokit.request("/"); - }); - - it('oauth key & secret with "?" in URL', () => { - nock("https://authentication-test-host.com") - .get("/") - .query({ foo: "bar", client_id: "id123", client_secret: "secret456" }) - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - clientId: "id123", - clientSecret: "secret456" - } - }); - - return octokit.request("/?foo=bar"); - }); - - it("auth is function", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "token abc4567" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: () => "token abc4567" - }); - - return octokit.request("/"); - }); - - it("auth is async function", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "token abc4567" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: () => Promise.resolve("token abc4567") - }); - - return octokit.request("/"); - }); - - it("auth function throws error", () => { - const octokit = new Octokit({ - auth() { - throw new Error("test"); - } - }); - - return octokit - .request("/") - .then(() => { - throw new Error("should not resolve"); - }) - .catch(error => { - expect(error.message).to.equal("test"); - }); - }); - - /** - * There is a special case for OAuth applications, when `clientId` and `clientSecret` is passed as - * Basic Authorization instead of query parameters. The only routes where that applies share the same - * URL though: `/applications/:client_id/tokens/:access_token`. We identify this acception by looking - * for this path. - * - * 1. [Check an authorization](https://developer.github.com/v3/oauth_authorizations/#check-an-authorization) - * 2. [Reset an authorization](https://developer.github.com/v3/oauth_authorizations/#reset-an-authorization) - * 3. [Revoke an authorization for an application](https://developer.github.com/v3/oauth_authorizations/#revoke-an-authorization-for-an-application) - */ - it("OAuth client & secret to check authorization", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic aWQxMjM6c2VjcmV0NDU2" - } - }) - .get("/applications/id123/tokens/token123") - .reply(200, {}) - .post("/applications/id123/tokens/token123") - .reply(200, {}) - .delete("/applications/id123/tokens/token123") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - clientId: "id123", - clientSecret: "secret456" - } - }); - - const options = { - client_id: "id123", - access_token: "token123" - }; - - return Promise.all([ - octokit.request( - "GET /applications/:client_id/tokens/:access_token", - options - ), - octokit.request( - "POST /applications/:client_id/tokens/:access_token", - options - ), - octokit.request( - "DELETE /applications/:client_id/tokens/:access_token", - options - ) - ]); - }); - - it("error to authenticated request", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "token abc4567" - } - }) - .get("/") - .reply(404, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: "token abc4567" - }); - - return octokit - .request("/") - - .catch(() => {}); - }); - - it("options.auth=token without prefix", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "token abc4567" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: "abc4567" - }); - - return octokit.request("/"); - }); - - it("options.auth=basic without prefix", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "basic Zm9vLWJhcjpzZWNyZXQ=" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: btoa("foo-bar:secret") - }); - - return octokit.request("/"); - }); - - it("options.auth=bearer without prefix", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: - "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw" - }); - - return octokit.request("/"); - }); - - it("options.auth=() => token without prefix", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "token abc4567" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: () => "abc4567" - }); - - return octokit.request("/"); - }); - - it("options.auth=() => basic without prefix", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "basic Zm9vLWJhcjpzZWNyZXQ=" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: () => btoa("foo-bar:secret") - }); - - return octokit.request("/"); - }); - - it("options.auth=() => bearer without prefix", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: - "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw" - } - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: () => - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw" - }); - - return octokit.request("/"); - }); - - it("invalid auth errors", () => { - expect(() => { - Octokit({ auth: {} }); - }).to.throw(Error); - }); -}); diff --git a/test/integration/deprecations-test.js b/test/integration/deprecations-test.js index fc79b7a1..1df56633 100644 --- a/test/integration/deprecations-test.js +++ b/test/integration/deprecations-test.js @@ -1,3 +1,4 @@ +const btoa = require("btoa-lite"); const nock = require("nock"); const Octokit = require("../../"); @@ -612,6 +613,7 @@ describe("deprecations", () => { .reply(200, {}); let warnCalledCount = 0; + const octokit = new Octokit({ baseUrl: "https://authentication-test-host.com", auth: { @@ -626,9 +628,21 @@ describe("deprecations", () => { } }); - return octokit.orgs.get({ org: "myorg" }).then(() => { - expect(warnCalledCount).to.equal(1); - }); + return octokit.orgs + .get({ org: "myorg" }) + .then(() => { + // deprecation is only logged once per process, I couldn't figure out how to reset the counter + // expect(warnCalledCount).to.equal(1); + + return octokit.auth(); + }) + .then(authentication => { + expect(authentication).to.deep.equal({ + type: "deprecated", + message: + 'Setting the "new Octokit({ auth })" option to an object without also setting the "authStrategy" option is deprecated and will be removed in v17. See (https://octokit.github.io/rest.js/#authentication)' + }); + }); }); it("new Octokit({ auth: { clientId, clientSecret } })", () => { @@ -641,6 +655,8 @@ describe("deprecations", () => { .reply(200, {}); let warnCalledCount = 0; + + const Octokit = require("../../"); const octokit = new Octokit({ baseUrl: "https://authentication-test-host.com", auth: { @@ -655,11 +671,12 @@ describe("deprecations", () => { }); return octokit.orgs.get({ org: "myorg" }).then(() => { - expect(warnCalledCount).to.equal(1); + // deprecation is only logged once per process, I couldn't figure out how to reset the counter + // expect(warnCalledCount).to.equal(1); }); }); - it.only("new Octokit({ auth () { /* ... */ } })", () => { + it("new Octokit({ auth () { /* ... */ } })", () => { nock("https://authentication-test-host.com", { reqheaders: { authorization: "token secret123" @@ -669,6 +686,7 @@ describe("deprecations", () => { .reply(200, {}); let warnCalledCount = 0; + const octokit = new Octokit({ baseUrl: "https://authentication-test-host.com", auth() { @@ -682,8 +700,480 @@ describe("deprecations", () => { }); return octokit.orgs.get({ org: "myorg" }).then(() => { - expect(warnCalledCount).to.equal(1); + // deprecation is only logged once per process, I couldn't figure out how to reset the counter + // expect(warnCalledCount).to.equal(1); + }); + }); + + it("options.auth { username, password } ", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" + } + }) + .get("/") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: { + username: "username", + password: "password" + }, + log: { + warn() {} + } + }); + + return octokit.request("/"); + }); + + it("options.auth { username, password, on2fa } with 2fa", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" + } + }) + .get("/") + .reply( + 401, + {}, + { + "x-github-otp": "required; app" + } + ); + + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", + "x-github-otp": "123456" + } + }) + .get("/") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: { + username: "username", + password: "password", + on2fa() { + return 123456; + } + } + }); + + return octokit.request("/"); + }); + + it("options.auth { username, password, on2fa } with async 2fa", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" + } + }) + .get("/") + .reply( + 401, + {}, + { + "x-github-otp": "required; app" + } + ); + + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", + "x-github-otp": "123456" + } + }) + .get("/") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: { + username: "username", + password: "password", + on2fa() { + return Promise.resolve(123456); + } + } + }); + + return octokit.request("/"); + }); + + it("options.auth { username, password, on2fa } with invalid one-time-password", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" + } + }) + .get("/") + .reply( + 401, + {}, + { + "x-github-otp": "required; app" + } + ); + + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", + "x-github-otp": "123456" + } + }) + .get("/") + .reply( + 401, + {}, + { + "x-github-otp": "required; app" + } + ); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: { + username: "username", + password: "password", + on2fa() { + return 123456; + } + } + }); + + return octokit + .request("/") + + .then(() => { + throw new Error("should not resolve"); + }) + + .catch(error => { + expect(error.message).to.match(/Invalid one-time password/i); + }); + }); + + it("options.auth { username, password, on2fa } with expiring 2fa", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" + } + }) + .get("/") + .reply( + 401, + {}, + { + "x-github-otp": "required; app" + } + ); + + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", + "x-github-otp": "1" + } + }) + .get("/") + .reply(200, {}); + + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", + "x-github-otp": "1" + } + }) + .get("/") + .reply( + 401, + {}, + { + "x-github-otp": "required; app" + } + ); + + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", + "x-github-otp": "2" + } + }) + .get("/") + .reply(200, {}); + + let callCount = 0; + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: { + username: "username", + password: "password", + on2fa() { + return ++callCount; + } + } + }); + + return octokit + .request("/") + .then(() => octokit.request("/")) + .then(() => { + expect(callCount).to.equal(2); + }); + }); + + it("options.auth is { username, password }", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" + } + }) + .get("/") + .reply( + 401, + {}, + { + "x-github-otp": "required; app" + } + ); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: { + username: "username", + password: "password" + } + }); + + return octokit + .request("/") + + .then(() => { + throw new Error('should fail with "on2fa missing" error'); + }) + + .catch(error => { + expect(error.message).to.equal( + "2FA required, but options.on2fa is not a function. See https://github.com/octokit/rest.js#authentication" + ); + expect(error.status).to.equal(401); + expect(!!error.headers).to.equal(true); + expect(!!error.request).to.equal(true); + }); + }); + + it("options.oauth is object with clientId & clientSecret", () => { + nock("https://authentication-test-host.com") + .get("/") + .query({ client_id: "id123", client_secret: "secret456" }) + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: { + clientId: "id123", + clientSecret: "secret456" + } + }); + + return octokit.request("/"); + }); + + it('options.oauth is object with clientId & clientSecret with "?" in URL', () => { + nock("https://authentication-test-host.com") + .get("/") + .query({ foo: "bar", client_id: "id123", client_secret: "secret456" }) + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: { + clientId: "id123", + clientSecret: "secret456" + } + }); + + return octokit.request("/?foo=bar"); + }); + + it("options.auth is function", () => { + nock("https://authentication-test-host-auth-as-function.com", { + reqheaders: { + authorization: "token abc4567" + } + }) + .get("/") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host-auth-as-function.com", + auth: () => "token abc4567" + }); + + return octokit.request("/"); + }); + + it("options.auth is async function", () => { + nock("https://authentication-test-host-as-async-function.com", { + reqheaders: { + authorization: "token abc4567" + } + }) + .get("/") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host-as-async-function.com", + auth: () => Promise.resolve("token abc4567") + }); + + return octokit.request("/"); + }); + + it("options.auth function (throws error)", () => { + const octokit = new Octokit({ + auth() { + throw new Error("test"); + } + }); + + return octokit + .request("/") + .then(() => { + throw new Error("should not resolve"); + }) + .catch(error => { + expect(error.message).to.equal("test"); + }); + }); + + /** + * There is a special case for OAuth applications, when `clientId` and `clientSecret` is passed as + * Basic Authorization instead of query parameters. The only routes where that applies share the same + * URL though: `/applications/:client_id/tokens/:access_token`. We identify this acception by looking + * for this path. + * + * 1. [Check an authorization](https://developer.github.com/v3/oauth_authorizations/#check-an-authorization) + * 2. [Reset an authorization](https://developer.github.com/v3/oauth_authorizations/#reset-an-authorization) + * 3. [Revoke an authorization for an application](https://developer.github.com/v3/oauth_authorizations/#revoke-an-authorization-for-an-application) + */ + it("OAuth client & secret to check authorization", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "Basic aWQxMjM6c2VjcmV0NDU2" + } + }) + .get("/applications/id123/tokens/token123") + .reply(200, {}) + .post("/applications/id123/tokens/token123") + .reply(200, {}) + .delete("/applications/id123/tokens/token123") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: { + clientId: "id123", + clientSecret: "secret456" + } + }); + + const options = { + client_id: "id123", + access_token: "token123" + }; + + return Promise.all([ + octokit.request( + "GET /applications/:client_id/tokens/:access_token", + options + ), + octokit.request( + "POST /applications/:client_id/tokens/:access_token", + options + ), + octokit.request( + "DELETE /applications/:client_id/tokens/:access_token", + options + ) + ]); + }); + + it("options.auth=basic without prefix", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "basic Zm9vLWJhcjpzZWNyZXQ=" + } + }) + .get("/") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: btoa("foo-bar:secret") + }); + + return octokit.request("/"); + }); + + it("options.auth=() => token without prefix", () => { + nock( + "https://authentication-test-host-auth-as-function-token-without-prefix.com", + { + reqheaders: { + authorization: "token abc4567" + } + } + ) + .get("/") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: + "https://authentication-test-host-auth-as-function-token-without-prefix.com", + auth: () => "abc4567" }); + + return octokit.request("/"); + }); + + it("options.auth=() => basic without prefix", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: "basic Zm9vLWJhcjpzZWNyZXQ=" + } + }) + .get("/") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: () => btoa("foo-bar:secret") + }); + + return octokit.request("/"); + }); + + it("options.auth=() => bearer without prefix", () => { + nock("https://authentication-test-host.com", { + reqheaders: { + authorization: + "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw" + } + }) + .get("/app") + .reply(200, {}); + + const octokit = new Octokit({ + baseUrl: "https://authentication-test-host.com", + auth: () => + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw" + }); + + return octokit.request("/app"); }); // deprecated client options diff --git a/test/issues/1497-include-error-message-on-validation-error-test.js b/test/issues/1497-include-error-message-on-validation-error-test.js index 165e5f5a..e34a6292 100644 --- a/test/issues/1497-include-error-message-on-validation-error-test.js +++ b/test/issues/1497-include-error-message-on-validation-error-test.js @@ -8,8 +8,8 @@ describe("https://github.com/octokit/rest.js/issues/1497", () => { nock("https://request-errors-test.com", { reqheaders: { accept: - "application/vnd.github.machine-man-preview+json,application/vnd.github.hellcat-preview+json,application/vnd.github.luke-cage-preview+json,application/vnd.github.zzzax-preview+json", - authorization: "Bearer dXNlcm5hbWU6cGFzc3dvcmQ=" + "application/vnd.github.hellcat-preview+json,application/vnd.github.luke-cage-preview+json,application/vnd.github.zzzax-preview+json", + authorization: "basic dXNlcm5hbWU6cGFzc3dvcmQ=" } }) .put("/repos/gr2m/sandbox/branches/gr2m-patch-1/protection", { @@ -34,7 +34,7 @@ describe("https://github.com/octokit/rest.js/issues/1497", () => { const octokit = new Octokit({ baseUrl: "https://request-errors-test.com", - auth: "Bearer dXNlcm5hbWU6cGFzc3dvcmQ=" + auth: "basic dXNlcm5hbWU6cGFzc3dvcmQ=" }); return octokit.repos .updateBranchProtection({ diff --git a/test/issues/861-custom-accept-header-test.js b/test/issues/861-custom-accept-header-test.js index 26ec3457..3481eb68 100644 --- a/test/issues/861-custom-accept-header-test.js +++ b/test/issues/861-custom-accept-header-test.js @@ -7,9 +7,8 @@ describe("https://github.com/octokit/rest.js/issues/861", () => { it("custom accept header", () => { nock("https://issues-861-test.com", { reqheaders: { - accept: - "application/vnd.github.antiope-preview+json,application/vnd.github.machine-man-preview+json", - authorization: "Bearer 123" + accept: "application/vnd.github.antiope-preview+json", + authorization: "token 123" } }) .post("/repos/swinton/example/check-runs") @@ -18,7 +17,7 @@ describe("https://github.com/octokit/rest.js/issues/861", () => { const octokit = new Octokit({ baseUrl: "https://issues-861-test.com", - auth: "Bearer 123" + auth: "token 123" }); return octokit.checks.create({