Skip to content

Commit 586c735

Browse files
committed
feat(pat): generates PAT
1 parent 2de90f6 commit 586c735

10 files changed

+180
-115
lines changed

package-lock.json

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

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"dependencies": {
5353
"babel-plugin-transform-runtime": "^6.23.0",
5454
"chalk": "^2.3.0",
55+
"clipboardy": "^1.2.3",
5556
"colors": "^1.1.2",
5657
"commander": "^2.12.1",
5758
"github": "^13.1.0",

src/createPersonalAccessToken.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,46 @@
1+
import { write } from 'clipboardy';
2+
3+
import promptReason from './prompters/reason';
14
import promptBasicPermissions from './prompters/basicPermissions';
5+
import { promptBasicAuthentication } from './prompters/basicAuthentication';
6+
import { promptTwoFactorAuthenticationCode } from './prompters/twoFactorAuthenticationCode';
7+
8+
import generateToken from './tokenGenerator';
9+
10+
const isTwoFactorAuthenticationError = error => (
11+
!!error
12+
&& !!error.message
13+
&& JSON.parse(error.message).message === 'Must specify two-factor authentication OTP code.'
14+
);
215

316
const createPersonalAccessToken = async () => {
17+
const { username, password } = await promptBasicAuthentication();
418
const { scopes } = await promptBasicPermissions();
19+
const { reason } = await promptReason();
20+
21+
try {
22+
const { token } = await generateToken({
23+
username,
24+
password,
25+
scopes,
26+
reason,
27+
});
28+
await write(token);
29+
} catch (error) {
30+
if (isTwoFactorAuthenticationError(error)) {
31+
const { twoFactorAuthenticationCode } = await promptTwoFactorAuthenticationCode();
32+
const { token } = await generateToken({
33+
username,
34+
password,
35+
scopes,
36+
reason,
37+
twoFactorAuthenticationCode,
38+
});
39+
await write(token);
40+
} else {
41+
throw error;
42+
}
43+
}
544
};
645

746
export default createPersonalAccessToken;

src/prompters/basicPermissions.js

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import inquirer from 'inquirer';
22

33
import {
4-
READ_ONLY_SCOPE,
54
REPOSITORY_SCOPE,
65
ORGANIZATION_SCOPE,
76
PUBLIC_KEY_SCOPE,
@@ -14,7 +13,6 @@ import {
1413
GPG_KEY_SCOPE,
1514
} from '../scopes';
1615

17-
const READ_ONLY_ACCESS = 'Read-only access to public information';
1816
const REPOSITORY_FULL_ACCESS = 'Full control of all repositories';
1917
const ORGANIZATION_FULL_ACCESS = 'Full control of orgs and teams';
2018
const PUBLIC_KEY_FULL_ACCESS = 'Full control of user public keys';
@@ -27,7 +25,6 @@ const DISCUSSIONS_FULL_ACCESS = 'Read and write team discussions';
2725
const GPG_KEYS_FULL_ACCESS = 'Full control of user gpg keys';
2826

2927
const choices = [
30-
READ_ONLY_ACCESS,
3128
REPOSITORY_FULL_ACCESS,
3229
ORGANIZATION_FULL_ACCESS,
3330
PUBLIC_KEY_FULL_ACCESS,
@@ -45,17 +42,16 @@ const defaults = [
4542
];
4643

4744
const choicesToScopes = Object.freeze({
48-
READ_ONLY_ACCESS: READ_ONLY_SCOPE,
49-
REPOSITORY_FULL_ACCESS: REPOSITORY_SCOPE.EVERYTHING,
50-
ORGANIZATION_FULL_ACCESS: ORGANIZATION_SCOPE.EVERYTHING,
51-
PUBLIC_KEY_FULL_ACCESS: PUBLIC_KEY_SCOPE.EVERYTHING,
52-
REPOSITORY_HOOK_FULL_ACCESS: REPOSITORY_HOOK_SCOPE.EVERYTHING,
53-
CREATE_GISTS: GIST_SCOPE,
54-
ACCESS_NOTIFICATIONS: NOTIFICATIONS_SCOPE,
55-
USER_FULL_ACCESS: USER_SCOPE.EVERYTHING,
56-
DELETE_REPOSITORIES: DELETE_REPOSITORY_SCOPE,
57-
DISCUSSIONS_FULL_ACCESS: DISCUSSION_SCOPE.EVERYTHING,
58-
GPG_KEYS_FULL_ACCESS: GPG_KEY_SCOPE.EVERYTHING,
45+
[REPOSITORY_FULL_ACCESS]: REPOSITORY_SCOPE.EVERYTHING,
46+
[ORGANIZATION_FULL_ACCESS]: ORGANIZATION_SCOPE.EVERYTHING,
47+
[PUBLIC_KEY_FULL_ACCESS]: PUBLIC_KEY_SCOPE.EVERYTHING,
48+
[REPOSITORY_HOOK_FULL_ACCESS]: REPOSITORY_HOOK_SCOPE.EVERYTHING,
49+
[CREATE_GISTS]: GIST_SCOPE,
50+
[ACCESS_NOTIFICATIONS]: NOTIFICATIONS_SCOPE,
51+
[USER_FULL_ACCESS]: USER_SCOPE.EVERYTHING,
52+
[DELETE_REPOSITORIES]: DELETE_REPOSITORY_SCOPE,
53+
[DISCUSSIONS_FULL_ACCESS]: DISCUSSION_SCOPE.EVERYTHING,
54+
[GPG_KEYS_FULL_ACCESS]: GPG_KEY_SCOPE.EVERYTHING,
5955
});
6056

6157
const promptBasicPermissions = async () => {

src/prompters/organizationPermissions.js

Lines changed: 0 additions & 36 deletions
This file was deleted.

src/prompters/reason.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import inquirer from 'inquirer';
2+
3+
const promptReason = async () => (
4+
inquirer.prompt([
5+
{
6+
name: 'reason',
7+
message: 'Reason for Personal Access Token',
8+
type: 'input',
9+
validate: answer => answer && answer.length > 0,
10+
},
11+
])
12+
);
13+
14+
export default promptReason;

src/prompters/repositoryPermissions.js

Lines changed: 0 additions & 44 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import inquirer from 'inquirer';
2+
3+
const validateAuthenticationCode = code => !!code && code.length > 0;
4+
5+
const promptTwoFactorAuthenticationCode = async () => (
6+
inquirer.prompt([
7+
{
8+
name: 'twoFactorAuthenticationCode',
9+
validate: validateAuthenticationCode,
10+
type: 'password',
11+
message: 'Enter your two-factor authentication code',
12+
},
13+
])
14+
);
15+
16+
export { validateAuthenticationCode, promptTwoFactorAuthenticationCode };

0 commit comments

Comments
 (0)