Skip to content

Commit d0b4f3b

Browse files
committed
Merge branch 'main' of https://github.com/atlassian/atlascode into AXON-128-add-lint-rule-for-unused-variables
2 parents 463c1e6 + 14ef897 commit d0b4f3b

File tree

8 files changed

+355
-783
lines changed

8 files changed

+355
-783
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## What's new in 3.4.5
2+
3+
### Bug Fixes
4+
5+
- Fixed bitbucket PR erroring out due to deprecated API being used
6+
17
## What's new in 3.4.4
28

39
### Bug Fixes

package-lock.json

Lines changed: 61 additions & 761 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1486,6 +1486,7 @@
14861486
},
14871487
"devDependencies": {
14881488
"@babel/core": "^7.25.0",
1489+
"@jest/globals": "^29.7.0",
14891490
"@stylistic/eslint-plugin-js": "^2.8.0",
14901491
"@types/analytics-node": "^3.1.7",
14911492
"@types/chai": "^4",
@@ -1495,7 +1496,7 @@
14951496
"@types/git-url-parse": "^9.0.1",
14961497
"@types/glob": "^7.1.1",
14971498
"@types/html-webpack-plugin": "^3.2.2",
1498-
"@types/jest": "^25.1.3",
1499+
"@types/jest": "^29.5.14",
14991500
"@types/jquery": "^3.3.23",
15001501
"@types/lodash.debounce": "^4.0.6",
15011502
"@types/lodash.orderby": "^4.6.6",

src/atlclients/strategy.test.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
jest.mock('./strategyCrypto', () => {
2+
return {
3+
createVerifier: jest.fn(() => 'verifier'),
4+
base64URLEncode: jest.fn(() => 'base64URLEncode'),
5+
sha256: jest.fn(() => 'sha256'),
6+
basicAuth: jest.fn(() => 'basicAuth'),
7+
};
8+
});
9+
10+
import { OAuthProvider } from './authInfo';
11+
import { strategyForProvider } from './strategy';
12+
13+
// it.each is not found without this:
14+
import { it } from '@jest/globals';
15+
16+
const expectedData = {
17+
bbcloud: {
18+
provider: 'bbcloud',
19+
authorizeUrl:
20+
'https://bitbucket.org/site/oauth2/authorize?client_id=3hasX42a7Ugka2FJja&response_type=code&state=state',
21+
accessibleResourcesUrl: '',
22+
tokenAuthorizationData: 'grant_type=authorization_code&code=code',
23+
tokenUrl: 'https://bitbucket.org/site/oauth2/access_token',
24+
apiUrl: 'https://bitbucket.org',
25+
refreshHeaders: {
26+
'Content-Type': 'application/x-www-form-urlencoded',
27+
Authorization: 'basicAuth',
28+
},
29+
tokenRefreshData: 'grant_type=refresh_token&refresh_token=refreshToken',
30+
profileUrl: 'https://api.bitbucket.org/2.0/user',
31+
emailsUrl: 'https://api.bitbucket.org/2.0/user/emails',
32+
},
33+
bbcloudstaging: {
34+
provider: 'bbcloudstaging',
35+
authorizeUrl:
36+
'https://staging.bb-inf.net/site/oauth2/authorize?client_id=7jspxC7fgemuUbnWQL&response_type=code&state=state',
37+
accessibleResourcesUrl: '',
38+
tokenAuthorizationData: 'grant_type=authorization_code&code=code',
39+
tokenUrl: 'https://staging.bb-inf.net/site/oauth2/access_token',
40+
apiUrl: 'https://staging.bb-inf.net',
41+
refreshHeaders: {
42+
'Content-Type': 'application/x-www-form-urlencoded',
43+
Authorization: 'basicAuth',
44+
},
45+
tokenRefreshData: 'grant_type=refresh_token&refresh_token=refreshToken',
46+
profileUrl: 'https://api-staging.bb-inf.net/2.0/user',
47+
emailsUrl: 'https://api-staging.bb-inf.net/2.0/user/emails',
48+
},
49+
jiracloud: {
50+
provider: 'jiracloud',
51+
authorizeUrl:
52+
'https://auth.atlassian.com/authorize?client_id=bJChVgBQd0aNUPuFZ8YzYBVZz3X4QTe2&redirect_uri=http%3A%2F%2F127.0.0.1%3A31415%2Fjiracloud&response_type=code&scope=read%3Ajira-user+read%3Ajira-work+write%3Ajira-work+offline_access+manage%3Ajira-project&audience=api.atlassian.com&prompt=consent&state=state&code_challenge=base64URLEncode&code_challenge_method=S256',
53+
accessibleResourcesUrl: 'https://api.atlassian.com/oauth/token/accessible-resources',
54+
tokenAuthorizationData:
55+
'{"grant_type":"authorization_code","code":"code","redirect_uri":"http://127.0.0.1:31415/jiracloud","client_id":"bJChVgBQd0aNUPuFZ8YzYBVZz3X4QTe2","code_verifier":"verifier"}',
56+
tokenUrl: 'https://auth.atlassian.com/oauth/token',
57+
apiUrl: 'api.atlassian.com',
58+
refreshHeaders: {
59+
'Content-Type': 'application/json',
60+
},
61+
tokenRefreshData:
62+
'{"grant_type":"refresh_token","client_id":"bJChVgBQd0aNUPuFZ8YzYBVZz3X4QTe2","refresh_token":"refreshToken"}',
63+
profileUrl: '',
64+
emailsUrl: '',
65+
},
66+
jiracloudstaging: {
67+
provider: 'jiracloudstaging',
68+
authorizeUrl:
69+
'https://auth.stg.atlassian.com/authorize?client_id=pmzXmUav3Rr5XEL0Sie7Biec0WGU8BKg&redirect_uri=http%3A%2F%2F127.0.0.1%3A31415%2Fjiracloudstaging&response_type=code&scope=read%3Ajira-user+read%3Ajira-work+write%3Ajira-work+offline_access+manage%3Ajira-project&audience=api.stg.atlassian.com&prompt=consent&state=state&code_challenge=base64URLEncode&code_challenge_method=S256',
70+
accessibleResourcesUrl: 'https://api.stg.atlassian.com/oauth/token/accessible-resources',
71+
tokenAuthorizationData:
72+
'{"grant_type":"authorization_code","code":"code","redirect_uri":"http://127.0.0.1:31415/jiracloudstaging","client_id":"pmzXmUav3Rr5XEL0Sie7Biec0WGU8BKg","code_verifier":"verifier"}',
73+
tokenUrl: 'https://auth.stg.atlassian.com/oauth/token',
74+
apiUrl: 'api.stg.atlassian.com',
75+
refreshHeaders: {
76+
'Content-Type': 'application/json',
77+
},
78+
tokenRefreshData:
79+
'{"grant_type":"refresh_token","client_id":"pmzXmUav3Rr5XEL0Sie7Biec0WGU8BKg","refresh_token":"refreshToken"}',
80+
profileUrl: '',
81+
emailsUrl: '',
82+
},
83+
};
84+
85+
describe('Authentication strategies', () => {
86+
it.each([
87+
[OAuthProvider.BitbucketCloud],
88+
[OAuthProvider.BitbucketCloudStaging],
89+
[OAuthProvider.JiraCloud],
90+
[OAuthProvider.JiraCloudStaging],
91+
])('Strategy for provider %s yields expected results', (provider: OAuthProvider) => {
92+
const expected = expectedData[provider] as any;
93+
const strategy = strategyForProvider(provider);
94+
expect(strategy.provider()).toBe(expected.provider);
95+
expect(strategy.authorizeUrl('state')).toBe(expected.authorizeUrl);
96+
expect(strategy.accessibleResourcesUrl()).toBe(expected.accessibleResourcesUrl);
97+
expect(strategy.tokenAuthorizationData('code')).toBe(expected.tokenAuthorizationData);
98+
expect(strategy.tokenUrl()).toBe(expected.tokenUrl);
99+
expect(strategy.apiUrl()).toBe(expected.apiUrl);
100+
expect(strategy.refreshHeaders()).toStrictEqual(expected.refreshHeaders);
101+
expect(strategy.tokenRefreshData('refreshToken')).toBe(expected.tokenRefreshData);
102+
expect(strategy.profileUrl()).toBe(expected.profileUrl);
103+
expect(strategy.emailsUrl()).toBe(expected.emailsUrl);
104+
});
105+
});

src/atlclients/strategy.ts

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { OAuthProvider } from './authInfo';
2-
import crypto from 'crypto';
2+
import { createVerifier, base64URLEncode, sha256, basicAuth } from './strategyCrypto';
33

44
const JiraProdStrategyData = {
55
clientID: 'bJChVgBQd0aNUPuFZ8YzYBVZz3X4QTe2',
@@ -90,7 +90,7 @@ class PKCEJiraProdStrategy extends Strategy {
9090

9191
public constructor() {
9292
super();
93-
this.verifier = base64URLEncode(crypto.randomBytes(32));
93+
this.verifier = createVerifier();
9494
}
9595

9696
public provider(): OAuthProvider {
@@ -151,20 +151,12 @@ class PKCEJiraProdStrategy extends Strategy {
151151
}
152152
}
153153

154-
function base64URLEncode(str: Buffer): string {
155-
return str.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
156-
}
157-
158-
function sha256(buffer: any) {
159-
return crypto.createHash('sha256').update(buffer).digest();
160-
}
161-
162154
class PKCEJiraStagingStrategy extends Strategy {
163155
private verifier: string;
164156

165157
public constructor() {
166158
super();
167-
this.verifier = base64URLEncode(crypto.randomBytes(32));
159+
this.verifier = createVerifier();
168160
}
169161

170162
public provider(): OAuthProvider {
@@ -258,12 +250,9 @@ class BitbucketProdStrategy extends Strategy {
258250

259251
// We kinda abuse refreshHeaders for bitbucket. Maybe have a authorizationHeaders as well? Just rename?
260252
public refreshHeaders() {
261-
const basicAuth = Buffer.from(
262-
`${BitbucketProdStrategyData.clientID}:${BitbucketProdStrategyData.clientSecret}`,
263-
).toString('base64');
264253
return {
265254
'Content-Type': 'application/x-www-form-urlencoded',
266-
Authorization: `Basic ${basicAuth}`,
255+
Authorization: basicAuth(BitbucketProdStrategyData.clientID, BitbucketProdStrategyData.clientSecret),
267256
};
268257
}
269258

@@ -311,12 +300,9 @@ class BitbucketStagingStrategy extends Strategy {
311300
}
312301

313302
public refreshHeaders() {
314-
const basicAuth = Buffer.from(
315-
`${BitbucketStagingStrategyData.clientID}:${BitbucketStagingStrategyData.clientSecret}`,
316-
).toString('base64');
317303
return {
318304
'Content-Type': 'application/x-www-form-urlencoded',
319-
Authorization: `Basic ${basicAuth}`,
305+
Authorization: basicAuth(BitbucketStagingStrategyData.clientID, BitbucketStagingStrategyData.clientSecret),
320306
};
321307
}
322308

src/atlclients/strategyCrypto.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import crypto from 'crypto';
2+
3+
// for some reason jest doesn't play nice with crypto,
4+
// so these are now in a separate file for easy mocking
5+
6+
export function createVerifier() {
7+
return base64URLEncode(crypto.randomBytes(32));
8+
}
9+
10+
export function base64URLEncode(str: Buffer): string {
11+
return str.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
12+
}
13+
14+
export function sha256(buffer: any) {
15+
return crypto.createHash('sha256').update(buffer).digest();
16+
}
17+
18+
export function basicAuth(username: string, password: string) {
19+
return 'Basic ' + Buffer.from(username + ':' + password).toString('base64');
20+
}

0 commit comments

Comments
 (0)