atlassian-connect-auth
Advanced tools
Comparing version 1.1.0 to 1.1.1
@@ -49,3 +49,3 @@ const jwt = require('atlassian-jwt') | ||
test('Unknown issuer', async () => { | ||
const loadCredentials = () => null | ||
const loadCredentials = jest.fn() | ||
const token = jwt.encode({ | ||
@@ -66,5 +66,8 @@ iss: jiraPayload.clientKey | ||
) | ||
expect(loadCredentials).toHaveBeenCalledWith(req.body.clientKey) | ||
}) | ||
test('Invalid signature', async () => { | ||
const loadCredentials = jest.fn().mockReturnValue(jiraPayload) | ||
const token = jwt.encode({ | ||
@@ -80,5 +83,3 @@ iss: jiraPayload.clientKey | ||
await expect(jiraAddon.auth(req, { | ||
loadCredentials: () => jiraPayload | ||
})).rejects.toMatchError( | ||
await expect(jiraAddon.auth(req, { loadCredentials })).rejects.toMatchError( | ||
new AuthError( | ||
@@ -92,5 +93,7 @@ 'Invalid signature', | ||
) | ||
expect(loadCredentials).toHaveBeenCalledWith(req.body.clientKey) | ||
}) | ||
test('Token expired', async () => { | ||
const loadCredentials = jest.fn().mockReturnValue(jiraPayload) | ||
const now = Math.floor(Date.now() / 1000) | ||
@@ -109,10 +112,10 @@ | ||
await expect(jiraAddon.auth(req, { | ||
loadCredentials: () => jiraPayload | ||
})).rejects.toMatchError( | ||
await expect(jiraAddon.auth(req, { loadCredentials })).rejects.toMatchError( | ||
new AuthError('Token expired', 'TOKEN_EXPIRED') | ||
) | ||
expect(loadCredentials).toHaveBeenCalledWith(req.body.clientKey) | ||
}) | ||
test('Invalid QSH', async () => { | ||
const loadCredentials = jest.fn().mockReturnValue(jiraPayload) | ||
const token = jwt.encode({ | ||
@@ -131,9 +134,11 @@ iss: jiraPayload.clientKey, | ||
await expect(jiraAddon.auth(req, { | ||
loadCredentials: () => jiraPayload | ||
loadCredentials | ||
})).rejects.toMatchError( | ||
new AuthError('Invalid QSH', 'INVALID_QSH') | ||
) | ||
expect(loadCredentials).toHaveBeenCalledWith(req.body.clientKey) | ||
}) | ||
test('No "qsh" in JWT token provided', async () => { | ||
const loadCredentials = jest.fn().mockReturnValue(jiraPayload) | ||
const token = jwt.encode({ | ||
@@ -151,3 +156,3 @@ iss: jiraPayload.clientKey | ||
const result = await jiraAddon.auth(req, { | ||
loadCredentials: () => jiraPayload | ||
loadCredentials | ||
}) | ||
@@ -157,5 +162,7 @@ | ||
expect(result).toHaveProperty('payload') | ||
expect(loadCredentials).toHaveBeenCalledWith(req.body.clientKey) | ||
}) | ||
test('"skipQsh" passed', async () => { | ||
const loadCredentials = jest.fn().mockReturnValue(jiraPayload) | ||
const token = jwt.encode({ | ||
@@ -173,3 +180,3 @@ iss: jiraPayload.clientKey | ||
const result = await jiraAddon.auth(req, { | ||
loadCredentials: () => jiraPayload, | ||
loadCredentials, | ||
skipQsh: true | ||
@@ -180,2 +187,3 @@ }) | ||
expect(result).toHaveProperty('payload') | ||
expect(loadCredentials).toHaveBeenCalledWith(req.body.clientKey) | ||
}) | ||
@@ -182,0 +190,0 @@ |
@@ -14,3 +14,4 @@ const jwt = require('atlassian-jwt') | ||
const bitbucketPayload = { | ||
principal: { uuid: 'bitbucket-workspace-id' } | ||
principal: { uuid: 'bitbucket-workspace-id' }, | ||
clientKey: 'bitbucket-client-key' | ||
} | ||
@@ -28,6 +29,10 @@ | ||
beforeEach(() => { | ||
saveCredentials.mockReset() | ||
}) | ||
describe('Installation', () => { | ||
test('First Jira add-on install', async () => { | ||
const req = { body: jiraPayload, headers: {}, query: {} } | ||
const loadCredentials = () => null | ||
const loadCredentials = jest.fn() | ||
@@ -40,2 +45,4 @@ const result = await jiraAddon.install(req, { | ||
expect(result.credentials).toEqual(jiraPayload) | ||
expect(loadCredentials).toHaveBeenCalledWith(req.body.clientKey) | ||
expect(saveCredentials).toHaveBeenCalledWith(req.body.clientKey, req.body) | ||
}) | ||
@@ -45,3 +52,3 @@ | ||
const req = { body: bitbucketPayload, headers: {}, query: {} } | ||
const loadCredentials = () => null | ||
const loadCredentials = jest.fn() | ||
@@ -54,2 +61,4 @@ const result = await bitbucketAddon.install(req, { | ||
expect(result.credentials).toEqual(bitbucketPayload) | ||
expect(loadCredentials).toHaveBeenCalledWith(req.body.clientKey) | ||
expect(saveCredentials).toHaveBeenCalledWith(req.body.clientKey, req.body) | ||
}) | ||
@@ -76,3 +85,3 @@ | ||
test('Passed different id in body and authorization header', async () => { | ||
const loadCredentials = () => null | ||
const loadCredentials = jest.fn() | ||
const token = jwt.encode({ | ||
@@ -94,6 +103,9 @@ iss: 'different-id' | ||
) | ||
expect(loadCredentials).toHaveBeenCalledWith(req.body.clientKey) | ||
expect(saveCredentials).not.toHaveBeenCalled() | ||
}) | ||
test('Second and subsequent Jira add-on install', async () => { | ||
const loadCredentials = () => jiraPayload | ||
const loadCredentials = jest.fn().mockReturnValue(jiraPayload) | ||
const token = jwt.encode({ | ||
@@ -114,2 +126,4 @@ iss: jiraPayload.clientKey | ||
expect(loadCredentials).toHaveBeenCalledWith(req.body.clientKey) | ||
expect(saveCredentials).toHaveBeenCalledWith(req.body.clientKey, req.body, jiraPayload) | ||
expect(result.credentials).toEqual(jiraPayload) | ||
@@ -122,3 +136,3 @@ expect(result.payload).toEqual({ | ||
test('Unauthorized request to updated existing instance', async () => { | ||
const loadCredentials = () => jiraPayload | ||
const loadCredentials = jest.fn().mockReturnValue(jiraPayload) | ||
const req = { body: jiraPayload, headers: {}, query: {} } | ||
@@ -132,3 +146,5 @@ | ||
) | ||
expect(loadCredentials).toHaveBeenCalledWith(req.body.clientKey) | ||
expect(saveCredentials).not.toHaveBeenCalled() | ||
}) | ||
}) |
@@ -11,14 +11,14 @@ const AuthError = require('./AuthError') | ||
async install (req, { loadCredentials, saveCredentials }) { | ||
const id = util.extractId(req, this.product) | ||
const clientKey = util.extractClientKey(req) | ||
const token = util.extractToken(req) | ||
const credentials = await loadCredentials(id) | ||
const credentials = await loadCredentials(clientKey) | ||
if (token && util.extractIssuer(token) !== id) { | ||
if (token && util.extractIssuer(token) !== clientKey) { | ||
throw new AuthError('Wrong issuer', 'WRONG_ISSUER') | ||
} | ||
// Create allowed if nothing was found by id. | ||
// Create allowed if nothing was found by clientKey. | ||
// Sometimes request signed (but we can't validate), sometimes not. | ||
if (!credentials) { | ||
const savedCredentials = await saveCredentials(id, req.body) | ||
const savedCredentials = await saveCredentials(clientKey, req.body) | ||
return { | ||
@@ -34,3 +34,4 @@ credentials: savedCredentials || req.body | ||
const updatedCredentials = await saveCredentials(id, req.body, credentials) | ||
const updatedCredentials = await saveCredentials(clientKey, req.body, credentials) | ||
return { | ||
@@ -46,3 +47,4 @@ credentials: updatedCredentials || req.body, | ||
async auth (req, { skipQsh, loadCredentials }) { | ||
const token = util.extractToken(req, this.product) | ||
const token = util.extractToken(req) | ||
if (!token) { | ||
@@ -52,4 +54,4 @@ throw new AuthError('Missed token', 'MISSED_TOKEN') | ||
const id = util.extractIssuer(token) | ||
const credentials = await loadCredentials(id) | ||
const clientKey = util.extractIssuer(token) | ||
const credentials = await loadCredentials(clientKey) | ||
@@ -56,0 +58,0 @@ if (!credentials) { |
@@ -9,7 +9,3 @@ const jwt = require('atlassian-jwt') | ||
function extractId (req, product) { | ||
if (product === 'bitbucket') { | ||
return req.body.principal.uuid | ||
} | ||
function extractClientKey (req) { | ||
return req.body.clientKey | ||
@@ -67,3 +63,3 @@ } | ||
extractToken, | ||
extractId, | ||
extractClientKey, | ||
extractIssuer, | ||
@@ -70,0 +66,0 @@ validateQsh, |
{ | ||
"name": "atlassian-connect-auth", | ||
"version": "1.1.0", | ||
"version": "1.1.1", | ||
"description": "Helper for handling webhooks from Atlassian products", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
# atlassian-connect-auth | ||
[](https://greenkeeper.io/) | ||
[](https://snyk.io/test/github/DanielHreben/atlassian-connect-auth?targetFile=package.json) | ||
@@ -8,7 +8,7 @@ Helper for handling webhooks from Atlassian products | ||
```javascript | ||
const {Addon, AuthError} = require('atlassian-connect-auth') | ||
const { Addon, AuthError } = require('atlassian-connect-auth') | ||
const addon = new Addon({ | ||
baseUrl: 'https://your-addon-url.com', | ||
product: 'jira', | ||
product: 'jira', // or 'bitbucket' | ||
}) | ||
@@ -63,4 +63,2 @@ | ||
.post('/api/hooks/jira/project/created', handleAuth, handleProjectCreated) | ||
``` | ||
``` |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
30418
476
0
63